Better segment handling in math signal and lock avoidance
authorSoeren Apel <soeren@apelpie.net>
Tue, 18 Aug 2020 06:38:33 +0000 (08:38 +0200)
committerSoeren Apel <soeren@apelpie.net>
Sat, 22 Aug 2020 22:16:19 +0000 (00:16 +0200)
pv/data/analog.cpp
pv/data/analog.hpp
pv/data/logicsegment.cpp
pv/data/mathsignal.cpp
pv/data/mathsignal.hpp
pv/data/segment.cpp
pv/data/segment.hpp

index 02cb83e40c7e474729c7c6d82035f673138f6d36..0b5c37729ea0908c4e6a3a2b39a727088de014a9 100644 (file)
@@ -39,6 +39,8 @@ Analog::Analog() :
 void Analog::push_segment(shared_ptr<AnalogSegment> &segment)
 {
        segments_.push_back(segment);
+
+       connect(segment.get(), SIGNAL(completed()), this, SLOT(on_segment_completed()));
 }
 
 const deque< shared_ptr<AnalogSegment> >& Analog::analog_segments() const
@@ -95,5 +97,10 @@ void Analog::notify_min_max_changed(float min, float max)
        min_max_changed(min, max);
 }
 
+void Analog::on_segment_completed()
+{
+       segment_completed();
+}
+
 } // namespace data
 } // namespace pv
index 630075da99a773f3d17183443a4d491b051d3816..630dc9db435bf36617aca313d220de8126a4ebdf 100644 (file)
@@ -73,6 +73,11 @@ Q_SIGNALS:
 
        void min_max_changed(float min, float max);
 
+       void segment_completed();
+
+private Q_SLOTS:
+       void on_segment_completed();
+
 private:
        double samplerate_;
        deque< shared_ptr<AnalogSegment> > segments_;
index a7df235a32d1c7a613de2824b14ca5ae6edff113..22f1d38a0095565cabdeb807180c0e7aff3c934d 100644 (file)
@@ -328,6 +328,7 @@ void LogicSegment::append_payload(shared_ptr<sigrok::Logic> logic)
 
 void LogicSegment::append_payload(void *data, uint64_t data_size)
 {
+       assert(unit_size_ > 0);
        assert((data_size % unit_size_) == 0);
 
        lock_guard<recursive_mutex> lock(mutex_);
index d9ba5bc369440e3ae051cc4ebecf517338d37484..24df0e71985b3688aa3d1953e323e13084d24d32 100644 (file)
@@ -101,8 +101,6 @@ MathSignal::MathSignal(pv::Session &session) :
                this, SLOT(on_capture_state_changed(int)));
        connect(&session_, SIGNAL(data_received()),
                this, SLOT(on_data_received()));
-
-       expression_ = "sin(2 * pi * t) + cos(t / 2 * pi)";
 }
 
 MathSignal::~MathSignal()
@@ -182,10 +180,18 @@ uint64_t MathSignal::get_working_sample_count(uint32_t segment_id) const
                                const shared_ptr<SignalBase>& sb = input_signal.second.sb;
 
                                shared_ptr<Analog> a = sb->analog_data();
-                               const uint32_t last_segment = (a->analog_segments().size() - 1);
-                               if (segment_id > last_segment)
+                               auto analog_segments = a->analog_segments();
+
+                               if (analog_segments.size() == 0) {
+                                       result = 0;
+                                       continue;
+                               }
+
+                               const uint32_t highest_segment_id = (analog_segments.size() - 1);
+                               if (segment_id > highest_segment_id)
                                        continue;
-                               const shared_ptr<AnalogSegment> segment = a->analog_segments()[segment_id];
+
+                               const shared_ptr<AnalogSegment> segment = analog_segments.at(segment_id);
                                result = min(result, (int64_t)segment->get_sample_count());
                        }
                } else
@@ -195,6 +201,38 @@ uint64_t MathSignal::get_working_sample_count(uint32_t segment_id) const
        return result;
 }
 
+void MathSignal::update_completeness(uint32_t segment_id)
+{
+       bool output_complete = true;
+
+       if (input_signals_.size() > 0) {
+               for (auto input_signal : input_signals_) {
+                       const shared_ptr<SignalBase>& sb = input_signal.second.sb;
+
+                       shared_ptr<Analog> a = sb->analog_data();
+                       auto analog_segments = a->analog_segments();
+
+                       if (analog_segments.size() == 0) {
+                               output_complete = false;
+                               continue;
+                       }
+
+                       const uint32_t highest_segment_id = (analog_segments.size() - 1);
+                       if (segment_id > highest_segment_id) {
+                               output_complete = false;
+                               continue;
+                       }
+
+                       const shared_ptr<AnalogSegment> segment = analog_segments.at(segment_id);
+                       if (!segment->is_complete())
+                               output_complete = false;
+               }
+       }
+
+       if (output_complete)
+               analog_data()->analog_segments().at(segment_id)->set_complete();
+}
+
 void MathSignal::reset_generation()
 {
        if (gen_thread_.joinable()) {
@@ -274,7 +312,7 @@ void MathSignal::begin_generation()
                        signal_data* sig_data = signal_from_name(unknown);
                        const shared_ptr<SignalBase> signal = (sig_data) ? (sig_data->sb) : nullptr;
                        if (!signal || (!signal->analog_data())) {
-                               set_error_message(QString(tr("%1 isn't a valid signal")).arg(
+                               set_error_message(QString(tr("%1 isn't a valid analog signal")).arg(
                                        QString::fromStdString(unknown)));
                        } else
                                sig_data->ref = &(exprtk_unknown_symbol_table_->variable_ref(unknown));
@@ -376,9 +414,9 @@ void MathSignal::generation_proc()
                }
 
                if (samples_to_process == 0) {
-                       if (segment_id < session_.get_highest_segment_id()) {
-                               analog->analog_segments().back()->set_complete();
+                       update_completeness(segment_id);
 
+                       if (segment_id < session_.get_highest_segment_id()) {
                                // Process next segment
                                segment_id++;
 
@@ -408,8 +446,15 @@ signal_data* MathSignal::signal_from_name(const std::string& name)
                const QString sig_name = QString::fromStdString(name);
 
                for (const shared_ptr<SignalBase>& sb : signalbases)
-                       if (sb->name() == sig_name)
+                       if (sb->name() == sig_name) {
+                               if (!sb->analog_data())
+                                       continue;
+
+                               connect(sb->analog_data().get(), SIGNAL(segment_completed()),
+                                       this, SLOT(on_data_received()));
+
                                return &(input_signals_.insert({name, signal_data(sb)}).first->second);
+                       }
        }
 
        return nullptr;
@@ -446,8 +491,12 @@ void MathSignal::on_capture_state_changed(int state)
                begin_generation();
 
        if (state == Session::Stopped) {
-               shared_ptr<Analog> analog = analog_data();
-               analog->analog_segments().back()->set_complete();
+               // If we have input signals, we use those as the indicators
+               if (input_signals_.empty()) {
+                       shared_ptr<Analog> analog = analog_data();
+                       if (!analog->analog_segments().empty())
+                               analog->analog_segments().back()->set_complete();
+               }
        }
 }
 
index b9bd6ee42427b705be56d87fff98c7a403125c97..a1fb9ffb899db98732e994d725ef91ba343a1dcf 100644 (file)
@@ -89,6 +89,8 @@ private:
         */
        uint64_t get_working_sample_count(uint32_t segment_id) const;
 
+       void update_completeness(uint32_t segment_id);
+
        void reset_generation();
        void begin_generation();
 
index 1dfdefd46704d030a2b950cfc9d0c2a219968d13..18aabedbedd348bf0656635f60cb991757713e32 100644 (file)
@@ -70,7 +70,6 @@ Segment::~Segment()
 
 uint64_t Segment::get_sample_count() const
 {
-       lock_guard<recursive_mutex> lock(mutex_);
        return sample_count_;
 }
 
@@ -102,6 +101,8 @@ uint32_t Segment::segment_id() const
 void Segment::set_complete()
 {
        is_complete_ = true;
+
+       completed();
 }
 
 bool Segment::is_complete() const
@@ -225,8 +226,7 @@ const uint8_t* Segment::get_raw_sample(uint64_t sample_num) const
        return chunk + chunk_offs;
 }
 
-void Segment::get_raw_samples(uint64_t start, uint64_t count,
-       uint8_t* dest) const
+void Segment::get_raw_samples(uint64_t start, uint64_t count, uint8_t* dest) const
 {
        assert(start < sample_count_);
        assert(start + count <= sample_count_);
index 9bdc17dd6f1c54fa854fd823eb12685e40763c7e..66085fafc935d151f5ded69cc7863bff984858a4 100644 (file)
 
 #include "pv/util.hpp"
 
+#include <atomic>
 #include <mutex>
 #include <thread>
 #include <deque>
 
 #include <QObject>
 
+using std::atomic;
 using std::recursive_mutex;
 using std::deque;
 
@@ -81,6 +83,9 @@ public:
 
        void free_unused_memory();
 
+Q_SIGNALS:
+       void completed();
+
 protected:
        void append_single_sample(void *data);
        void append_samples(void *data, uint64_t samples);
@@ -98,7 +103,7 @@ protected:
        deque<uint8_t*> data_chunks_;
        uint8_t* current_chunk_;
        uint64_t used_samples_, unused_samples_;
-       uint64_t sample_count_;
+       atomic<uint64_t> sample_count_;
        pv::util::Timestamp start_time_;
        double samplerate_;
        uint64_t chunk_size_;