]> sigrok.org Git - pulseview.git/commitdiff
Initial support for SRD_OUTPUT_LOGIC
authorSoeren Apel <redacted>
Sat, 3 Aug 2019 21:08:34 +0000 (23:08 +0200)
committerSoeren Apel <redacted>
Sat, 13 Feb 2021 21:37:41 +0000 (22:37 +0100)
pv/data/decode/decoder.cpp
pv/data/decode/decoder.hpp
pv/data/decodesignal.cpp
pv/data/decodesignal.hpp
pv/data/logicsegment.cpp
pv/data/logicsegment.hpp
pv/views/viewbase.hpp

index f644b8af3a3356e03db91af8b948119e2cb4be17..b1cf42d5d0edfa7810670500d444df3eead3848e 100644 (file)
@@ -327,6 +327,26 @@ void Decoder::on_class_visibility_changed()
        annotation_visibility_changed();
 }
 
+bool Decoder::has_logic_output() const
+{
+       return (srd_decoder_->logic_output_channels != nullptr);
+}
+
+const vector<DecoderLogicOutputChannel> Decoder::logic_output_channels() const
+{
+       vector<DecoderLogicOutputChannel> result;
+
+       for (GSList *l = srd_decoder_->logic_output_channels; l; l = l->next) {
+               const srd_decoder_logic_output_channel* ch_data =
+                       (srd_decoder_logic_output_channel*)l->data;
+
+               result.emplace_back(QString::fromUtf8(ch_data->id),
+                       QString::fromUtf8(ch_data->desc), ch_data->samplerate);
+       }
+
+       return result;
+}
+
 }  // namespace decode
 }  // namespace data
 }  // namespace pv
index 86a371f26c67c11d72abfe80a3715cf2292921ae..e86deccdcfc1a38c1097f1c2f7b886259687e160 100644 (file)
@@ -89,6 +89,13 @@ struct DecodeChannel
        const srd_channel *pdch_;
 };
 
+struct DecoderLogicOutputChannel {
+       DecoderLogicOutputChannel (QString id, QString desc, uint64_t sr) :
+               id(id), desc(desc), samplerate(sr) {};
+       QString id, desc;
+       uint64_t samplerate;
+};
+
 struct DecodeBinaryClassInfo
 {
        uint32_t bin_class_id;
@@ -139,6 +146,9 @@ public:
        uint32_t get_binary_class_count() const;
        const DecodeBinaryClassInfo* get_binary_class(uint32_t id) const;
 
+       bool has_logic_output() const;
+       const vector<DecoderLogicOutputChannel> logic_output_channels() const;
+
 Q_SIGNALS:
        void annotation_visibility_changed();
 
index 91bee1da35f5d022cdaf0ffbbe3c7bf48ab4a930..a3525922943a878b5d051fbdb724eb44a9f2100a 100644 (file)
@@ -33,6 +33,7 @@
 #include <pv/globalsettings.hpp>
 #include <pv/session.hpp>
 
+using std::dynamic_pointer_cast;
 using std::lock_guard;
 using std::make_shared;
 using std::min;
@@ -95,6 +96,7 @@ void DecodeSignal::stack_decoder(const srd_decoder *decoder, bool restart_decode
        stack_config_changed_ = true;
        auto_assign_signals(dec);
        commit_decoder_channels();
+       update_output_signals();
 
        decoder_stacked((void*)dec.get());
 
@@ -358,6 +360,53 @@ int DecodeSignal::get_assigned_signal_count() const
                [](decode::DecodeChannel ch) { return ch.assigned_signal.get(); });
 }
 
+void DecodeSignal::update_output_signals()
+{
+       for (const shared_ptr<decode::Decoder>& dec : stack_) {
+               assert(dec);
+
+               if (dec->has_logic_output()) {
+                       const vector<decode::DecoderLogicOutputChannel> logic_channels =
+                               dec->logic_output_channels();
+
+                       // All signals of a decoder share the same LogicSegment, so it's
+                       // sufficient to check for the first channel only
+                       const decode::DecoderLogicOutputChannel& first_ch = logic_channels[0];
+
+                       bool ch_exists = false;
+                       for (const shared_ptr<SignalBase>& signal : output_signals_)
+                               if (signal->internal_name() == first_ch.id)
+                                       ch_exists = true;
+
+                       if (!ch_exists) {
+                               shared_ptr<Logic> logic_data = make_shared<Logic>(logic_channels.size());
+                               output_logic_[dec->get_srd_decoder()] = logic_data;
+
+                               shared_ptr<LogicSegment> logic_segment = make_shared<data::LogicSegment>(
+                                       *logic_data, 0, (logic_data->num_channels() + 7) / 8, first_ch.samplerate);
+                               logic_data->push_segment(logic_segment);
+
+                               uint index = 0;
+                               for (const decode::DecoderLogicOutputChannel& logic_ch : logic_channels) {
+                                       shared_ptr<data::SignalBase> signal =
+                                               make_shared<data::SignalBase>(nullptr, LogicChannel);
+                                       signal->set_internal_name(logic_ch.id);
+                                       signal->set_name(logic_ch.id);
+                                       signal->set_index(index);
+                                       signal->set_data(logic_data);
+                                       output_signals_.push_back(signal);
+                                       session_.add_generated_signal(signal);
+                                       index++;
+                               }
+                       }
+               }
+       }
+
+       // TODO Delete signals that no longer have a corresponding decoder (also from session)
+       // TODO Check whether all sample rates are the same as the session's
+       // TODO Set colors to the same as the decoder's background color
+}
+
 void DecodeSignal::set_initial_pin_state(const uint16_t channel_id, const int init_state)
 {
        for (decode::DecodeChannel& ch : channels_)
@@ -731,6 +780,8 @@ void DecodeSignal::save_settings(QSettings &settings) const
 
                settings.endGroup();
        }
+
+       // TODO Save logic output signal settings
 }
 
 void DecodeSignal::restore_settings(QSettings &settings)
@@ -835,6 +886,9 @@ void DecodeSignal::restore_settings(QSettings &settings)
        stack_config_changed_ = true;
        update_channel_list();
        commit_decoder_channels();
+       update_output_signals();
+
+       // TODO Restore logic output signal settings
 
        begin_decode();
 }
@@ -1395,6 +1449,9 @@ void DecodeSignal::start_srd_session()
        srd_pd_output_callback_add(srd_session_, SRD_OUTPUT_BINARY,
                DecodeSignal::binary_callback, this);
 
+       srd_pd_output_callback_add(srd_session_, SRD_OUTPUT_LOGIC,
+               DecodeSignal::logic_output_callback, this);
+
        srd_session_start(srd_session_);
 
        // We just recreated the srd session, so all stack changes are applied now
@@ -1644,6 +1701,39 @@ void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal)
        ds->new_binary_data(ds->current_segment_id_, (void*)dec, pdb->bin_class);
 }
 
+void DecodeSignal::logic_output_callback(srd_proto_data *pdata, void *decode_signal)
+{
+       assert(pdata);
+       assert(decode_signal);
+
+       DecodeSignal *const ds = (DecodeSignal*)decode_signal;
+       assert(ds);
+
+       if (ds->decode_interrupt_)
+               return;
+
+       lock_guard<mutex> lock(ds->output_mutex_);
+
+       assert(pdata->pdo);
+       assert(pdata->pdo->di);
+       const srd_decoder *const decc = pdata->pdo->di->decoder;
+       assert(decc);
+
+       const srd_proto_data_logic *const pdl = (const srd_proto_data_logic*)pdata->data;
+       assert(pdl);
+
+       shared_ptr<Logic> output_logic = ds->output_logic_.at(decc);
+       shared_ptr<LogicSegment> last_segment =
+               dynamic_pointer_cast<LogicSegment>(output_logic->segments().back());
+       assert(last_segment);
+
+       last_segment->append_subsignal_payload(pdl->logic_class, (void*)pdl->data, pdl->size);
+
+       qInfo() << "Received" << pdl->size << "bytes /" << pdl->size \
+               << "samples of logic output for class" << pdl->logic_class << "from decoder" \
+               << QString::fromUtf8(decc->name);
+}
+
 void DecodeSignal::on_capture_state_changed(int state)
 {
        // If a new acquisition was started, we need to start decoding from scratch
index ab85246a0bc7aaf7d4a7a94059590fb42761f68a..ca9f9e96f652d7247d1856567990cb0c24f9914b 100644 (file)
@@ -121,6 +121,8 @@ public:
        void assign_signal(const uint16_t channel_id, shared_ptr<const SignalBase> signal);
        int get_assigned_signal_count() const;
 
+       void update_output_signals();
+
        void set_initial_pin_state(const uint16_t channel_id, const int init_state);
 
        virtual double get_samplerate() const;
@@ -216,6 +218,7 @@ private:
 
        static void annotation_callback(srd_proto_data *pdata, void *decode_signal);
        static void binary_callback(srd_proto_data *pdata, void *decode_signal);
+       static void logic_output_callback(srd_proto_data *pdata, void *decode_signal);
 
 Q_SIGNALS:
        void decoder_stacked(void* decoder); ///< decoder is of type decode::Decoder*
@@ -260,6 +263,9 @@ private:
        atomic<bool> decode_interrupt_, logic_mux_interrupt_;
 
        bool decode_paused_;
+
+       map<const srd_decoder*, shared_ptr<Logic>> output_logic_;
+       vector< shared_ptr<SignalBase>> output_signals_;
 };
 
 } // namespace data
index d000922787daf1346307738658d25f5e3288bac6..354c14f85d8bef035fd3a184757aabfb5d304c0b 100644 (file)
@@ -363,6 +363,29 @@ void LogicSegment::append_payload(void *data, uint64_t data_size)
                        prev_sample_count + 1, prev_sample_count + 1);
 }
 
+void LogicSegment::append_subsignal_payload(unsigned int index, void *data, uint64_t data_size)
+{
+       static vector<uint8_t> merged_data;  // Using static also places it on the heap
+
+       for (uint64_t i = 0; i < data_size * unit_size_; i++)
+               merged_data.emplace_back(0);
+
+       // Set the bits for this sub-signal where needed
+       // Note: the bytes in *data must either be 0 or 1, nothing else
+       unsigned int index_byte = index / 8;
+       for (uint64_t i = 0; i < data_size; i++) {
+               unsigned int offs = i * unit_size_ + index_byte;
+               uint8_t* data_byte = merged_data.data() + offs;
+               *data_byte |= *((uint8_t*)data + i) << index;
+       }
+
+       if (index == owner_.num_channels() - 1) {
+               // We gathered sample data of all sub-signals, let's append it
+               append_payload(merged_data.data(), merged_data.size());
+               merged_data.clear();
+       }
+}
+
 void LogicSegment::get_samples(int64_t start_sample,
        int64_t end_sample, uint8_t* dest) const
 {
index 2e37ed2d248df56c22d1e0d1cd703d7835425fcb..2b67c0edb81ddad6165597499bf4d704d185a483 100644 (file)
@@ -86,6 +86,18 @@ public:
        void append_payload(shared_ptr<sigrok::Logic> logic);
        void append_payload(void *data, uint64_t data_size);
 
+       /**
+        * Appends sample data for a single channel where each byte
+        * represents one sample - if it's 0 the state is low, if 1 high.
+        * Other values are not permitted.
+        * Assumes that all channels are having samples added and in the
+        * order of 0..n, not n..0.
+        * Also assumes the the number of samples added for each channel
+        * is constant for every invokation for 0..n. The number of samples
+        * hence may only change when index is 0.
+        */
+       void append_subsignal_payload(unsigned int index, void *data, uint64_t data_size);
+
        void get_samples(int64_t start_sample, int64_t end_sample, uint8_t* dest) const;
 
        /**
index eff962311cc549434e51dc48db45f6bda704c5bc..972b04ea6ed4cf8d99e3f9b83d192175ceea8269 100644 (file)
@@ -91,15 +91,12 @@ public:
        vector< shared_ptr<data::SignalBase> > signalbases() const;
 
        virtual void clear_signalbases();
-
        virtual void add_signalbase(const shared_ptr<data::SignalBase> signalbase);
        virtual void remove_signalbase(const shared_ptr<data::SignalBase> signalbase);
 
 #ifdef ENABLE_DECODE
        virtual void clear_decode_signals();
-
        virtual void add_decode_signal(shared_ptr<data::DecodeSignal> signal);
-
        virtual void remove_decode_signal(shared_ptr<data::DecodeSignal> signal);
 #endif