Implement Trace::ShowLastCompleteSegmentOnly display mode
authorSoeren Apel <soeren@apelpie.net>
Thu, 28 Dec 2017 16:37:48 +0000 (17:37 +0100)
committerSoeren Apel <soeren@apelpie.net>
Fri, 5 Jan 2018 21:50:35 +0000 (22:50 +0100)
14 files changed:
pv/data/segment.cpp
pv/data/segment.hpp
pv/data/signalbase.cpp
pv/data/signalbase.hpp
pv/session.cpp
pv/session.hpp
pv/views/trace/analogsignal.cpp
pv/views/trace/logicsignal.cpp
pv/views/trace/standardbar.cpp
pv/views/trace/trace.hpp
pv/views/trace/view.cpp
pv/views/trace/view.hpp
pv/views/viewbase.cpp
pv/views/viewbase.hpp

index ae9788fc676724d06166f8ffd851767f5abe6362..8745e8740dc582f8a53d33ae7ed8e81d36a87398 100644 (file)
@@ -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<recursive_mutex> 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<recursive_mutex> lock(mutex_);
index db75ef710a285ceb75f795667a0826d34f4b8e1b..62750c11c9c62e0d0de0f948e8d4896417970a22 100644 (file)
@@ -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;
index 9f47a9755eee6fc6ec085e3a831fb51062971183..26e01d05828858e1e1e1e00df28ee3162f5c3018 100644 (file)
@@ -201,6 +201,35 @@ shared_ptr<data::Logic> 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<Analog> data = dynamic_pointer_cast<Analog>(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<Logic> data = dynamic_pointer_cast<Logic>(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_;
index 977a9cd68121f743e7e7070d67957e9d7e07081e..6a3af14b3f0115c64dee8f1438fc21accfc37168 100644 (file)
@@ -175,6 +175,12 @@ public:
         */
        shared_ptr<pv::data::Logic> 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.
         */
index a44c6f9916f3b326a05e932950cee0acfacedf40..605cc05c65fd8ab234f5509d5885f30f276f805d 100644 (file)
@@ -988,6 +988,27 @@ void Session::signal_new_segment()
        }
 }
 
+void Session::signal_segment_completed()
+{
+       int segment_id = 0;
+
+       for (shared_ptr<data::SignalBase> 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<recursive_mutex> lock(data_mutex_);
+
+               if (cur_logic_segment_)
+                       cur_logic_segment_->set_complete();
+
+               for (auto entry : cur_analog_segments_) {
+                       shared_ptr<data::AnalogSegment> 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> logic)
index 76019612a977eaff33fed75c6c5d932897863a2a..8ae6673872f3c5a4804672a9a6a2b976d6b57396 100644 (file)
@@ -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();
 
index cb4c0325e3e83fd42fbd7335d09cf77faee4bef0..e6bd875600130141e5789f9f9b7626aec3c0b75c 100644 (file)
@@ -658,7 +658,8 @@ shared_ptr<pv::data::AnalogSegment> 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<pv::data::LogicSegment> 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) {
index bbb00ef6ad862f6fa27a0e6c0cdb498080c921c7..99900941918b9b8058fce31b52f68ddd8275ac8b 100644 (file)
@@ -358,7 +358,8 @@ shared_ptr<pv::data::LogicSegment> 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) {
index 65f9ae3e684d57434667ed4c48666a6cc3cf30bf..9d4d0e4add5fca735778b0d9fd2bbf2feeeada4a 100644 (file)
@@ -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
index cd1c8af349f7014b80547549ed462f33eba63d16..777ea5001198a3cb355540006a43bfbc2f222e82 100644 (file)
@@ -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
index f350459c500bdb9190d44fa0cad0e04a4e1200ad..58056e5c9a82279285a4357de17d91b9b0bf5329 100644 (file)
@@ -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> signal : signals_)
+               signal->set_current_segment(current_segment_);
+       for (shared_ptr<DecodeTrace> 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> signal : signals_)
-                       signal->set_current_segment(current_segment_);
-               for (shared_ptr<DecodeTrace> 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> signal : signals_)
+                               if (!signal->base()->segment_is_complete(segment))
+                                       all_complete = false;
+
+                       if (all_complete)
+                               set_current_segment(segment);
+               }
                break;
 
        case Trace::ShowAllSegments:
index da05691f42f5274b8c8fd86d54ffeccd80230927..712151dcae30fc2d11a503a04cc90e4ea697f236 100644 (file)
@@ -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_;
index 30fd7cec7a59fddcf80ae729614cbe4f67161a9d..7d986fe051e730b55034bb423a0afdc1ca058c87 100644 (file)
@@ -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;
index fdf12a8693d20505d417346b74587dc6d2e43995..8e71f3bbe221c9b05a0ee36cd84c7a713483e974 100644 (file)
@@ -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: