From: Soeren Apel Date: Fri, 7 Apr 2017 20:18:38 +0000 (+0200) Subject: Introduce DecodeSignal class X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=ad908057e13224eee9f983685e0ccc7db1ded0e9;p=pulseview.git Introduce DecodeSignal class For starters, we equip it with some basic wrappers around the decode stack, rework the annotation signal a little and use the new DecodeSignal in favor of the SignalBase class. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index ca4142c4..b51753b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,6 +334,7 @@ endif() if(ENABLE_DECODE) list(APPEND pulseview_SOURCES pv/binding/decoder.cpp + pv/data/decodesignal.cpp pv/data/decoderstack.cpp pv/data/decode/annotation.cpp pv/data/decode/decoder.cpp @@ -345,6 +346,7 @@ if(ENABLE_DECODE) ) list(APPEND pulseview_HEADERS + pv/data/decodesignal.hpp pv/data/decoderstack.hpp pv/views/trace/decodetrace.hpp pv/widgets/decodergroupbox.hpp diff --git a/pv/data/decoderstack.cpp b/pv/data/decoderstack.cpp index 1e1d600d..c7504f58 100644 --- a/pv/data/decoderstack.cpp +++ b/pv/data/decoderstack.cpp @@ -157,6 +157,11 @@ vector DecoderStack::get_visible_rows() const return rows; } +uint64_t DecoderStack::inc_annotation_count() +{ + return (annotation_count_++); +} + void DecoderStack::get_annotation_subset( vector &dest, const Row &row, uint64_t start_sample, @@ -179,6 +184,7 @@ QString DecoderStack::error_message() void DecoderStack::clear() { sample_count_ = 0; + annotation_count_ = 0; frame_complete_ = false; samples_decoded_ = 0; error_message_ = QString(); @@ -324,12 +330,7 @@ void DecoderStack::decode_data( lock_guard lock(output_mutex_); samples_decoded_ = chunk_end; } - - if (i % DecodeNotifyPeriod == 0) - new_decode_data(); } - - new_decode_data(); } void DecoderStack::decode_proc() @@ -386,19 +387,22 @@ void DecoderStack::decode_proc() abs_start_samplenum = *sample_count; } while (error_message_.isEmpty() && (sample_count = wait_for_data())); + // Make sure all annotations are known to the frontend + new_annotations(); + // Destroy the session srd_session_destroy(session); } -void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) +void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder_stack) { assert(pdata); assert(decoder); - DecoderStack *const d = (DecoderStack*)decoder; - assert(d); + DecoderStack *const ds = (DecoderStack*)decoder_stack; + assert(ds); - lock_guard lock(d->output_mutex_); + lock_guard lock(ds->output_mutex_); const Annotation a(pdata); @@ -408,19 +412,19 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) const srd_decoder *const decc = pdata->pdo->di->decoder; assert(decc); - auto row_iter = d->rows_.end(); + auto row_iter = ds->rows_.end(); // Try looking up the sub-row of this class - const auto r = d->class_rows_.find(make_pair(decc, a.format())); - if (r != d->class_rows_.end()) - row_iter = d->rows_.find((*r).second); + const auto r = ds->class_rows_.find(make_pair(decc, a.format())); + if (r != ds->class_rows_.end()) + row_iter = ds->rows_.find((*r).second); else { // Failing that, use the decoder as a key - row_iter = d->rows_.find(Row(decc)); + row_iter = ds->rows_.find(Row(decc)); } - assert(row_iter != d->rows_.end()); - if (row_iter == d->rows_.end()) { + assert(row_iter != ds->rows_.end()); + if (row_iter == ds->rows_.end()) { qDebug() << "Unexpected annotation: decoder = " << decc << ", format = " << a.format(); assert(false); @@ -429,6 +433,10 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) // Add the annotation (*row_iter).second.push_annotation(a); + + // Notify the frontend every DecodeNotifyPeriod annotations + if (ds->inc_annotation_count() % DecodeNotifyPeriod == 0) + ds->new_annotations(); } void DecoderStack::on_new_frame() diff --git a/pv/data/decoderstack.hpp b/pv/data/decoderstack.hpp index 5216006e..37e4888f 100644 --- a/pv/data/decoderstack.hpp +++ b/pv/data/decoderstack.hpp @@ -103,6 +103,13 @@ public: vector get_visible_rows() const; + /** + * Helper function for static annotation_callback(), + * must be public so the function can access it. + * Don't use from outside this class. + */ + uint64_t inc_annotation_count(); + /** * Extracts sorted annotations between two period into a vector. */ @@ -127,7 +134,7 @@ private: void decode_proc(); - static void annotation_callback(srd_proto_data *pdata, void *decoder); + static void annotation_callback(srd_proto_data *pdata, void *decoder_stack); private Q_SLOTS: void on_new_frame(); @@ -137,7 +144,7 @@ private Q_SLOTS: void on_frame_ended(); Q_SIGNALS: - void new_decode_data(); + void new_annotations(); private: pv::Session &session_; @@ -159,7 +166,7 @@ private: mutable mutex input_mutex_; mutable condition_variable input_cond_; - int64_t sample_count_; + int64_t sample_count_, annotation_count_; bool frame_complete_; mutable mutex output_mutex_; diff --git a/pv/data/decodesignal.cpp b/pv/data/decodesignal.cpp new file mode 100644 index 00000000..bc453d21 --- /dev/null +++ b/pv/data/decodesignal.cpp @@ -0,0 +1,102 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2017 Soeren Apel + * + * 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, see . + */ + +#include "logic.hpp" +#include "logicsegment.hpp" +#include "decodesignal.hpp" +#include "signaldata.hpp" + +#include +#include +#include +#include + +using std::make_shared; +using std::shared_ptr; +using pv::data::decode::Decoder; + +namespace pv { +namespace data { + +DecodeSignal::DecodeSignal(shared_ptr decoder_stack) : + SignalBase(nullptr, SignalBase::DecodeChannel), + decoder_stack_(decoder_stack) +{ + set_name(QString::fromUtf8(decoder_stack_->stack().front()->decoder()->name)); + + connect(decoder_stack_.get(), SIGNAL(new_annotations()), + this, SLOT(on_new_annotations())); +} + +DecodeSignal::~DecodeSignal() +{ +} + +bool DecodeSignal::is_decode_signal() const +{ + return true; +} + +shared_ptr DecodeSignal::decoder_stack() const +{ + return decoder_stack_; +} + +void DecodeSignal::stack_decoder(srd_decoder *decoder) +{ + assert(decoder); + assert(decoder_stack); + decoder_stack_->push(make_shared(decoder)); + decoder_stack_->begin_decode(); +} + +void DecodeSignal::remove_decoder(int index) +{ + decoder_stack_->remove(index); + decoder_stack_->begin_decode(); +} + +bool DecodeSignal::toggle_decoder_visibility(int index) +{ + const list< shared_ptr > stack(decoder_stack_->stack()); + + auto iter = stack.cbegin(); + for (int i = 0; i < index; i++, iter++) + assert(iter != stack.end()); + + shared_ptr dec = *iter; + + // Toggle decoder visibility + bool state = false; + if (dec) { + state = !dec->shown(); + dec->show(state); + } + + return state; +} + +void DecodeSignal::on_new_annotations() +{ + // Forward the signal to the frontend + new_annotations(); +} + +} // namespace data +} // namespace pv diff --git a/pv/data/decodesignal.hpp b/pv/data/decodesignal.hpp new file mode 100644 index 00000000..23ab209b --- /dev/null +++ b/pv/data/decodesignal.hpp @@ -0,0 +1,64 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2017 Soeren Apel + * + * 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, see . + */ + +#ifndef PULSEVIEW_PV_DATA_DECODESIGNAL_HPP +#define PULSEVIEW_PV_DATA_DECODESIGNAL_HPP + +#include + +#include + +using std::shared_ptr; + +namespace pv { +namespace data { + +class DecoderStack; +class Logic; +class SignalData; + +class DecodeSignal : public SignalBase +{ + Q_OBJECT + +public: + DecodeSignal(shared_ptr decoder_stack); + virtual ~DecodeSignal(); + + bool is_decode_signal() const; + shared_ptr decoder_stack() const; + + void stack_decoder(srd_decoder *decoder); + void remove_decoder(int index); + bool toggle_decoder_visibility(int index); + +Q_SIGNALS: + void new_annotations(); + +private Q_SLOTS: + void on_new_annotations(); + +private: + shared_ptr decoder_stack_; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_DECODESIGNAL_HPP diff --git a/pv/data/signalbase.cpp b/pv/data/signalbase.cpp index c8a6d556..8693c58b 100644 --- a/pv/data/signalbase.cpp +++ b/pv/data/signalbase.cpp @@ -200,18 +200,14 @@ void SignalBase::set_conversion_type(ConversionType t) #ifdef ENABLE_DECODE bool SignalBase::is_decode_signal() const { - return (decoder_stack_ != nullptr); + // DecodeSignal class overrides this method, all others shall return false + return false; } shared_ptr SignalBase::decoder_stack() const { - return decoder_stack_; -} - -void SignalBase::set_decoder_stack(shared_ptr - decoder_stack) -{ - decoder_stack_ = decoder_stack; + // DecodeSignal class overrides this method, all others shall return nothing + return nullptr; } #endif diff --git a/pv/data/signalbase.hpp b/pv/data/signalbase.hpp index e6726c5a..97dbd847 100644 --- a/pv/data/signalbase.hpp +++ b/pv/data/signalbase.hpp @@ -148,11 +148,9 @@ public: void set_conversion_type(ConversionType t); #ifdef ENABLE_DECODE - bool is_decode_signal() const; + virtual bool is_decode_signal() const; - shared_ptr decoder_stack() const; - - void set_decoder_stack(shared_ptr decoder_stack); + virtual shared_ptr decoder_stack() const; #endif void save_settings(QSettings &settings) const; @@ -189,17 +187,13 @@ private Q_SLOTS: void on_capture_state_changed(int state); -private: +protected: shared_ptr channel_; ChannelType channel_type_; shared_ptr data_; shared_ptr converted_data_; int conversion_type_; -#ifdef ENABLE_DECODE - shared_ptr decoder_stack_; -#endif - std::thread conversion_thread_; QString internal_name_, name_; diff --git a/pv/session.cpp b/pv/session.cpp index 00eb7ad0..fa5f95bb 100644 --- a/pv/session.cpp +++ b/pv/session.cpp @@ -53,6 +53,7 @@ #ifdef ENABLE_DECODE #include +#include "data/decodesignal.hpp" #endif using std::bad_alloc; @@ -687,14 +688,13 @@ bool Session::add_decoder(srd_decoder *const dec) decoder_stack->stack().front()->set_channels(channels); // Create the decode signal - shared_ptr signalbase = - make_shared(nullptr, data::SignalBase::DecodeChannel); + shared_ptr signal = + make_shared(decoder_stack); - signalbase->set_decoder_stack(decoder_stack); - signalbases_.insert(signalbase); + signalbases_.insert(signal); for (shared_ptr view : views_) - view->add_decode_signal(signalbase); + view->add_decode_signal(signal); } catch (runtime_error e) { return false; } @@ -707,12 +707,12 @@ bool Session::add_decoder(srd_decoder *const dec) return true; } -void Session::remove_decode_signal(shared_ptr signalbase) +void Session::remove_decode_signal(shared_ptr signal) { - signalbases_.erase(signalbase); + signalbases_.erase(signal); for (shared_ptr view : views_) - view->remove_decode_signal(signalbase); + view->remove_decode_signal(signal); signals_changed(); } diff --git a/pv/session.hpp b/pv/session.hpp index c4f2bed8..5a54d83a 100644 --- a/pv/session.hpp +++ b/pv/session.hpp @@ -70,6 +70,7 @@ class DeviceManager; namespace data { class Analog; class AnalogSegment; +class DecodeSignal; class Logic; class LogicSegment; class SignalBase; @@ -171,7 +172,7 @@ public: #ifdef ENABLE_DECODE bool add_decoder(srd_decoder *const dec); - void remove_decode_signal(shared_ptr signalbase); + void remove_decode_signal(shared_ptr signal); #endif private: diff --git a/pv/views/trace/decodetrace.cpp b/pv/views/trace/decodetrace.cpp index ef821049..d151a92d 100644 --- a/pv/views/trace/decodetrace.cpp +++ b/pv/views/trace/decodetrace.cpp @@ -43,13 +43,14 @@ extern "C" { #include "viewport.hpp" #include +#include +#include +#include #include #include #include #include #include -#include -#include #include #include @@ -134,17 +135,16 @@ DecodeTrace::DecodeTrace(pv::Session &session, delete_mapper_(this), show_hide_mapper_(this) { - shared_ptr decoder_stack = base_->decoder_stack(); + decode_signal_ = dynamic_pointer_cast(base_); // Determine shortest string we want to see displayed in full QFontMetrics m(QApplication::font()); min_useful_label_width_ = m.width("XX"); // e.g. two hex characters - base_->set_name(QString::fromUtf8(decoder_stack->stack().front()->decoder()->name)); base_->set_colour(DecodeColours[index % countof(DecodeColours)]); - connect(decoder_stack.get(), SIGNAL(new_decode_data()), - this, SLOT(on_new_decode_data())); + connect(decode_signal_.get(), SIGNAL(new_annotations()), + this, SLOT(on_new_annotations())); connect(&delete_mapper_, SIGNAL(mapped(int)), this, SLOT(on_delete_decoder(int))); connect(&show_hide_mapper_, SIGNAL(mapped(int)), @@ -985,7 +985,7 @@ void DecodeTrace::commit_channels() decoder_stack->begin_decode(); } -void DecodeTrace::on_new_decode_data() +void DecodeTrace::on_new_annotations() { if (owner_) owner_->row_item_appearance_changed(false, true); @@ -998,7 +998,7 @@ void DecodeTrace::delete_pressed() void DecodeTrace::on_delete() { - session_.remove_decode_signal(base_); + session_.remove_decode_signal(decode_signal_); } void DecodeTrace::on_channel_selected(int) @@ -1013,49 +1013,25 @@ void DecodeTrace::on_initial_pin_selected(int) void DecodeTrace::on_stack_decoder(srd_decoder *decoder) { - shared_ptr decoder_stack = base_->decoder_stack(); - - assert(decoder); - assert(decoder_stack); - decoder_stack->push(make_shared(decoder)); - decoder_stack->begin_decode(); + decode_signal_->stack_decoder(decoder); create_popup_form(); } void DecodeTrace::on_delete_decoder(int index) { - shared_ptr decoder_stack = base_->decoder_stack(); - - decoder_stack->remove(index); + decode_signal_->remove_decoder(index); // Update the popup create_popup_form(); - - decoder_stack->begin_decode(); } void DecodeTrace::on_show_hide_decoder(int index) { - using pv::data::decode::Decoder; - - shared_ptr decoder_stack = base_->decoder_stack(); - - const list< shared_ptr > stack(decoder_stack->stack()); - - // Find the decoder in the stack - auto iter = stack.cbegin(); - for (int i = 0; i < index; i++, iter++) - assert(iter != stack.end()); - - shared_ptr dec = *iter; - assert(dec); - - const bool show = !dec->shown(); - dec->show(show); + const bool state = decode_signal_->toggle_decoder_visibility(index); assert(index < (int)decoder_forms_.size()); - decoder_forms_[index]->set_decoder_visible(show); + decoder_forms_[index]->set_decoder_visible(state); if (owner_) owner_->row_item_appearance_changed(false, true); diff --git a/pv/views/trace/decodetrace.hpp b/pv/views/trace/decodetrace.hpp index e49d1229..e53e2b80 100644 --- a/pv/views/trace/decodetrace.hpp +++ b/pv/views/trace/decodetrace.hpp @@ -51,6 +51,7 @@ class Session; namespace data { class DecoderStack; class SignalBase; +class DecodeSignal; namespace decode { class Annotation; @@ -195,7 +196,7 @@ public: void hover_point_changed(); private Q_SLOTS: - void on_new_decode_data(); + void on_new_annotations(); void on_delete(); @@ -211,6 +212,7 @@ private Q_SLOTS: private: pv::Session &session_; + shared_ptr decode_signal_; vector visible_rows_; uint64_t decode_start_, decode_end_; diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp index f1f8eb0c..6218c2ef 100644 --- a/pv/views/trace/view.cpp +++ b/pv/views/trace/view.cpp @@ -262,17 +262,17 @@ void View::clear_decode_signals() decode_traces_.clear(); } -void View::add_decode_signal(shared_ptr signalbase) +void View::add_decode_signal(shared_ptr signal) { shared_ptr d( - new DecodeTrace(session_, signalbase, decode_traces_.size())); + new DecodeTrace(session_, signal, decode_traces_.size())); decode_traces_.push_back(d); } -void View::remove_decode_signal(shared_ptr signalbase) +void View::remove_decode_signal(shared_ptr signal) { for (auto i = decode_traces_.begin(); i != decode_traces_.end(); i++) - if ((*i)->base() == signalbase) { + if ((*i)->base() == signal) { decode_traces_.erase(i); signals_changed(); return; diff --git a/pv/views/trace/view.hpp b/pv/views/trace/view.hpp index bfa7ed3e..5be95957 100644 --- a/pv/views/trace/view.hpp +++ b/pv/views/trace/view.hpp @@ -116,9 +116,9 @@ public: #ifdef ENABLE_DECODE virtual void clear_decode_signals(); - virtual void add_decode_signal(shared_ptr signalbase); + virtual void add_decode_signal(shared_ptr signal); - virtual void remove_decode_signal(shared_ptr signalbase); + virtual void remove_decode_signal(shared_ptr signal); #endif /** diff --git a/pv/views/viewbase.cpp b/pv/views/viewbase.cpp index e86a543e..4031211f 100644 --- a/pv/views/viewbase.cpp +++ b/pv/views/viewbase.cpp @@ -97,14 +97,14 @@ void ViewBase::clear_decode_signals() { } -void ViewBase::add_decode_signal(shared_ptr signalbase) +void ViewBase::add_decode_signal(shared_ptr signal) { - (void)signalbase; + (void)signal; } -void ViewBase::remove_decode_signal(shared_ptr signalbase) +void ViewBase::remove_decode_signal(shared_ptr signal) { - (void)signalbase; + (void)signal; } #endif diff --git a/pv/views/viewbase.hpp b/pv/views/viewbase.hpp index 61430136..e6a003a5 100644 --- a/pv/views/viewbase.hpp +++ b/pv/views/viewbase.hpp @@ -32,6 +32,10 @@ #include #include +#ifdef ENABLE_DECODE +#include +#endif + using std::shared_ptr; using std::unordered_set; @@ -78,9 +82,9 @@ public: #ifdef ENABLE_DECODE virtual void clear_decode_signals(); - virtual void add_decode_signal(shared_ptr signalbase); + virtual void add_decode_signal(shared_ptr signal); - virtual void remove_decode_signal(shared_ptr signalbase); + virtual void remove_decode_signal(shared_ptr signal); #endif virtual void save_settings(QSettings &settings) const; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8cab18fe..896ba028 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -157,6 +157,7 @@ set(pulseview_TEST_HEADERS if(ENABLE_DECODE) list(APPEND pulseview_TEST_SOURCES ${PROJECT_SOURCE_DIR}/pv/binding/decoder.cpp + ${PROJECT_SOURCE_DIR}/pv/data/decodesignal.cpp ${PROJECT_SOURCE_DIR}/pv/data/decoderstack.cpp ${PROJECT_SOURCE_DIR}/pv/data/decode/annotation.cpp ${PROJECT_SOURCE_DIR}/pv/data/decode/decoder.cpp @@ -169,6 +170,7 @@ if(ENABLE_DECODE) ) list(APPEND pulseview_TEST_HEADERS + ${PROJECT_SOURCE_DIR}/pv/data/decodesignal.hpp ${PROJECT_SOURCE_DIR}/pv/data/decoderstack.hpp ${PROJECT_SOURCE_DIR}/pv/views/trace/decodetrace.hpp ${PROJECT_SOURCE_DIR}/pv/widgets/decodergroupbox.hpp