From: Soeren Apel Date: Thu, 28 Dec 2017 16:37:48 +0000 (+0100) Subject: Implement Trace::ShowLastCompleteSegmentOnly display mode X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=558ad6ceb934ab7406d286c1a4ae08da4aba1448;p=pulseview.git Implement Trace::ShowLastCompleteSegmentOnly display mode --- diff --git a/pv/data/segment.cpp b/pv/data/segment.cpp index ae9788fc..8745e874 100644 --- a/pv/data/segment.cpp +++ b/pv/data/segment.cpp @@ -39,7 +39,8 @@ Segment::Segment(uint64_t samplerate, unsigned int unit_size) : samplerate_(samplerate), unit_size_(unit_size), iterator_count_(0), - mem_optimization_requested_(false) + mem_optimization_requested_(false), + is_complete_(false) { lock_guard lock(mutex_); assert(unit_size_ > 0); @@ -89,6 +90,16 @@ unsigned int Segment::unit_size() const return unit_size_; } +void Segment::set_complete() +{ + is_complete_ = true; +} + +bool Segment::is_complete() const +{ + return is_complete_; +} + void Segment::free_unused_memory() { lock_guard lock(mutex_); diff --git a/pv/data/segment.hpp b/pv/data/segment.hpp index db75ef71..62750c11 100644 --- a/pv/data/segment.hpp +++ b/pv/data/segment.hpp @@ -71,6 +71,9 @@ public: unsigned int unit_size() const; + void set_complete(); + bool is_complete() const; + void free_unused_memory(); protected: @@ -93,6 +96,7 @@ protected: unsigned int unit_size_; int iterator_count_; bool mem_optimization_requested_; + bool is_complete_; friend struct SegmentTest::SmallSize8Single; friend struct SegmentTest::MediumSize8Single; diff --git a/pv/data/signalbase.cpp b/pv/data/signalbase.cpp index 9f47a975..26e01d05 100644 --- a/pv/data/signalbase.cpp +++ b/pv/data/signalbase.cpp @@ -201,6 +201,35 @@ shared_ptr SignalBase::logic_data() const return result; } +bool SignalBase::segment_is_complete(uint32_t segment_id) const +{ + bool result = true; + + if (channel_type_ == AnalogChannel) + { + shared_ptr data = dynamic_pointer_cast(data_); + auto segments = data->analog_segments(); + try { + result = segments.at(segment_id)->is_complete(); + } catch (out_of_range) { + // Do nothing + } + } + + if (channel_type_ == LogicChannel) + { + shared_ptr data = dynamic_pointer_cast(data_); + auto segments = data->logic_segments(); + try { + result = segments.at(segment_id)->is_complete(); + } catch (out_of_range) { + // Do nothing + } + } + + return result; +} + SignalBase::ConversionType SignalBase::get_conversion_type() const { return conversion_type_; diff --git a/pv/data/signalbase.hpp b/pv/data/signalbase.hpp index 977a9cd6..6a3af14b 100644 --- a/pv/data/signalbase.hpp +++ b/pv/data/signalbase.hpp @@ -175,6 +175,12 @@ public: */ shared_ptr logic_data() const; + /** + * Determines whether a given segment is complete (i.e. end-of-frame has + * been seen). It only considers the original data, not the converted data. + */ + bool segment_is_complete(uint32_t segment_id) const; + /** * Queries the kind of conversion performed on this channel. */ diff --git a/pv/session.cpp b/pv/session.cpp index a44c6f99..605cc05c 100644 --- a/pv/session.cpp +++ b/pv/session.cpp @@ -988,6 +988,27 @@ void Session::signal_new_segment() } } +void Session::signal_segment_completed() +{ + int segment_id = 0; + + for (shared_ptr signalbase : signalbases_) { + // We only care about analog and logic channels, not derived ones + if (signalbase->type() == data::SignalBase::AnalogChannel) { + segment_id = signalbase->analog_data()->get_segment_count() - 1; + break; + } + + if (signalbase->type() == data::SignalBase::LogicChannel) { + segment_id = signalbase->logic_data()->get_segment_count() - 1; + break; + } + } + + if (segment_id >= 0) + segment_completed(segment_id); +} + void Session::feed_in_header() { // Nothing to do here for now @@ -1044,14 +1065,28 @@ void Session::feed_in_frame_begin() void Session::feed_in_frame_end() { + if (!frame_began_) + return; + { lock_guard lock(data_mutex_); + + if (cur_logic_segment_) + cur_logic_segment_->set_complete(); + + for (auto entry : cur_analog_segments_) { + shared_ptr segment = entry.second; + segment->set_complete(); + } + cur_logic_segment_.reset(); cur_analog_segments_.clear(); } if (frame_began_) frame_began_ = false; + + signal_segment_completed(); } void Session::feed_in_logic(shared_ptr logic) diff --git a/pv/session.hpp b/pv/session.hpp index 76019612..8ae66738 100644 --- a/pv/session.hpp +++ b/pv/session.hpp @@ -197,6 +197,7 @@ private: void free_unused_memory(); void signal_new_segment(); + void signal_segment_completed(); void feed_in_header(); @@ -255,6 +256,7 @@ Q_SIGNALS: void trigger_event(util::Timestamp location); void new_segment(int new_segment_id); + void segment_completed(int segment_id); void data_received(); diff --git a/pv/views/trace/analogsignal.cpp b/pv/views/trace/analogsignal.cpp index cb4c0325..e6bd8756 100644 --- a/pv/views/trace/analogsignal.cpp +++ b/pv/views/trace/analogsignal.cpp @@ -658,7 +658,8 @@ shared_ptr AnalogSignal::get_analog_segment_to_paint() if (segment_display_mode_ == ShowLastSegmentOnly) segment = segments.back(); - if (segment_display_mode_ == ShowSingleSegmentOnly) { + if ((segment_display_mode_ == ShowSingleSegmentOnly) || + (segment_display_mode_ == ShowLastCompleteSegmentOnly)) { try { segment = segments.at(current_segment_); } catch (out_of_range) { @@ -681,7 +682,8 @@ shared_ptr AnalogSignal::get_logic_segment_to_paint() co if (segment_display_mode_ == ShowLastSegmentOnly) segment = segments.back(); - if (segment_display_mode_ == ShowSingleSegmentOnly) { + if ((segment_display_mode_ == ShowSingleSegmentOnly) || + (segment_display_mode_ == ShowLastCompleteSegmentOnly)) { try { segment = segments.at(current_segment_); } catch (out_of_range) { diff --git a/pv/views/trace/logicsignal.cpp b/pv/views/trace/logicsignal.cpp index bbb00ef6..99900941 100644 --- a/pv/views/trace/logicsignal.cpp +++ b/pv/views/trace/logicsignal.cpp @@ -358,7 +358,8 @@ shared_ptr LogicSignal::get_logic_segment_to_paint() con segment = segments.back(); } - if (segment_display_mode_ == ShowSingleSegmentOnly) { + if ((segment_display_mode_ == ShowSingleSegmentOnly) || + (segment_display_mode_ == ShowLastCompleteSegmentOnly)) { try { segment = segments.at(current_segment_); } catch (out_of_range) { diff --git a/pv/views/trace/standardbar.cpp b/pv/views/trace/standardbar.cpp index 65f9ae3e..9d4d0e4a 100644 --- a/pv/views/trace/standardbar.cpp +++ b/pv/views/trace/standardbar.cpp @@ -90,6 +90,9 @@ StandardBar::StandardBar(Session &session, QWidget *parent, connect(&session_, SIGNAL(new_segment(int)), this, SLOT(on_new_segment(int))); + connect(&session_, SIGNAL(segment_completed(int)), + view_, SLOT(on_segment_completed(int))); + connect(segment_selector_, SIGNAL(valueChanged(int)), this, SLOT(on_segment_selected(int))); connect(view_, SIGNAL(segment_changed(int)), @@ -199,7 +202,7 @@ void StandardBar::on_always_zoom_to_fit_changed(bool state) void StandardBar::on_new_segment(int new_segment_id) { - if (new_segment_id > 1) { + if (new_segment_id > 0) { show_multi_segment_ui(true); segment_selector_->setMaximum(new_segment_id + 1); } else diff --git a/pv/views/trace/trace.hpp b/pv/views/trace/trace.hpp index cd1c8af3..777ea500 100644 --- a/pv/views/trace/trace.hpp +++ b/pv/views/trace/trace.hpp @@ -67,10 +67,16 @@ public: /** * Allowed values for the multi-segment display mode. * - * Note: Consider @ref View::set_segment_display_mode when updating the list. + * Note: Consider these locations when updating the list: + * * + * @ref View::set_segment_display_mode + * @ref AnalogSignal::get_analog_segment_to_paint + * @ref AnalogSignal::get_logic_segment_to_paint + * @ref LogicSignal::get_logic_segment_to_paint */ enum SegmentDisplayMode { ShowLastSegmentOnly = 1, + ShowLastCompleteSegmentOnly, ShowSingleSegmentOnly, ShowAllSegments, ShowAccumulatedIntensity diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp index f350459c..58056e5c 100644 --- a/pv/views/trace/view.cpp +++ b/pv/views/trace/view.cpp @@ -488,6 +488,18 @@ void View::set_time_unit(pv::util::TimeUnit time_unit) } } +void View::set_current_segment(uint32_t segment_id) +{ + current_segment_ = segment_id; + + for (shared_ptr signal : signals_) + signal->set_current_segment(current_segment_); + for (shared_ptr dt : decode_traces_) + dt->set_current_segment(current_segment_); + + viewport_->update(); +} + bool View::segment_is_selectable() const { return segment_selectable_; @@ -1384,6 +1396,10 @@ void View::capture_state_updated(int state) // Enable sticky scrolling if the setting is enabled sticky_scrolling_ = settings.value(GlobalSettings::Key_View_StickyScrolling).toBool(); + + // Reset all traces to segment 0 + current_segment_ = 0; + set_current_segment(current_segment_); } if (state == Session::Stopped) { @@ -1420,17 +1436,32 @@ void View::on_new_segment(int new_segment_id) segment_changed(new_segment_id); } +void View::on_segment_completed(int segment_id) +{ + on_segment_changed(segment_id); + segment_changed(segment_id); +} + void View::on_segment_changed(int segment) { switch (segment_display_mode_) { case Trace::ShowLastSegmentOnly: case Trace::ShowSingleSegmentOnly: - current_segment_ = segment; - for (shared_ptr signal : signals_) - signal->set_current_segment(current_segment_); - for (shared_ptr dt : decode_traces_) - dt->set_current_segment(current_segment_); - viewport_->update(); + set_current_segment(segment); + break; + + case Trace::ShowLastCompleteSegmentOnly: + { + // Only update if all segments are complete + bool all_complete = true; + + for (shared_ptr signal : signals_) + if (!signal->base()->segment_is_complete(segment)) + all_complete = false; + + if (all_complete) + set_current_segment(segment); + } break; case Trace::ShowAllSegments: diff --git a/pv/views/trace/view.hpp b/pv/views/trace/view.hpp index da05691f..712151dc 100644 --- a/pv/views/trace/view.hpp +++ b/pv/views/trace/view.hpp @@ -382,6 +382,7 @@ private Q_SLOTS: void capture_state_updated(int state); void on_new_segment(int new_segment_id); + void on_segment_completed(int new_segment_id); void on_segment_changed(int segment); virtual void perform_delayed_view_update(); @@ -424,6 +425,11 @@ private Q_SLOTS: */ void set_time_unit(pv::util::TimeUnit time_unit); + /** + * Sets the current segment with the first segment starting at 0. + */ + void set_current_segment(uint32_t segment_id); + private: CustomScrollArea *scrollarea_; Viewport *viewport_; diff --git a/pv/views/viewbase.cpp b/pv/views/viewbase.cpp index 30fd7cec..7d986fe0 100644 --- a/pv/views/viewbase.cpp +++ b/pv/views/viewbase.cpp @@ -134,6 +134,11 @@ void ViewBase::on_new_segment(int new_segment_id) (void)new_segment_id; } +void ViewBase::on_segment_completed(int new_segment_id) +{ + (void)new_segment_id; +} + void ViewBase::capture_state_updated(int state) { (void)state; diff --git a/pv/views/viewbase.hpp b/pv/views/viewbase.hpp index fdf12a86..8e71f3bb 100644 --- a/pv/views/viewbase.hpp +++ b/pv/views/viewbase.hpp @@ -96,6 +96,7 @@ public Q_SLOTS: virtual void signals_changed(); virtual void capture_state_updated(int state); virtual void on_new_segment(int new_segment_id); + virtual void on_segment_completed(int new_segment_id); virtual void perform_delayed_view_update(); private Q_SLOTS: