#include "decoder.hpp"
#include <pv/data/signalbase.hpp>
+#include <pv/data/decodesignal.hpp>
+using pv::data::DecodeChannel;
using std::set;
using std::map;
using std::shared_ptr;
shown_ = show;
}
-const map<const srd_channel*, shared_ptr<data::SignalBase> >&
-Decoder::channels() const
+const vector<DecodeChannel*>& Decoder::channels() const
{
return channels_;
}
-void Decoder::set_channels(map<const srd_channel*,
- shared_ptr<data::SignalBase> > channels)
+void Decoder::set_channels(vector<DecodeChannel*> channels)
{
channels_ = channels;
}
bool Decoder::have_required_channels() const
{
- for (GSList *l = decoder_->channels; l; l = l->next) {
- const srd_channel *const pdch = (const srd_channel*)l->data;
- assert(pdch);
- if (channels_.find(pdch) == channels_.end())
+ for (DecodeChannel *ch : channels_)
+ if (!ch->assigned_signal && !ch->is_optional)
return false;
- }
return true;
}
-set< shared_ptr<pv::data::Logic> > Decoder::get_data()
-{
- set< shared_ptr<pv::data::Logic> > data;
- for (const auto& channel : channels_) {
- shared_ptr<data::SignalBase> b(channel.second);
- assert(b);
- data.insert(b->logic_data());
- }
-
- return data;
-}
-
srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) const
{
GHashTable *const opt_hash = g_hash_table_new_full(g_str_hash,
GHashTable *const channels = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
- for (const auto& channel : channels_) {
- shared_ptr<data::SignalBase> b(channel.second);
-
-// init_pin_states->data[pdch->order] =
-// channel.initial_pin_state;
+ for (DecodeChannel *ch : channels_) {
+ init_pin_states->data[ch->id] = ch->initial_pin_state;
- GVariant *const gvar = g_variant_new_int32(b->index());
+ GVariant *const gvar = g_variant_new_int32(ch->id); // id = bit position
g_variant_ref_sink(gvar);
- g_hash_table_insert(channels, channel.first->id, gvar);
+ // key is channel name, value is bit position in each sample
+ g_hash_table_insert(channels, ch->pdch_->id, gvar);
}
srd_inst_channel_set_all(decoder_inst, channels);
-// srd_inst_initial_pins_set_all(decoder_inst, initial_pin_states);
+ srd_inst_initial_pins_set_all(decoder_inst, init_pin_states);
g_array_free(init_pin_states, TRUE);
return decoder_inst;
#include <map>
#include <memory>
#include <set>
+#include <vector>
#include <glib.h>
using std::set;
using std::shared_ptr;
using std::string;
+using std::vector;
struct srd_decoder;
struct srd_decoder_inst;
namespace data {
+struct DecodeChannel;
class Logic;
class SignalBase;
bool shown() const;
void show(bool show = true);
- const map<const srd_channel*,
- shared_ptr<data::SignalBase> >& channels() const;
- void set_channels(map<const srd_channel*,
- shared_ptr<data::SignalBase> > channels);
+ const vector<data::DecodeChannel*>& channels() const;
+ void set_channels(vector<data::DecodeChannel*> channels);
const map<string, GVariant*>& options() const;
srd_decoder_inst* create_decoder_inst(srd_session *session) const;
- set< shared_ptr<pv::data::Logic> > get_data();
-
private:
const srd_decoder *const decoder_;
bool shown_;
- map<const srd_channel*, shared_ptr<pv::data::SignalBase> > channels_;
+ vector<data::DecodeChannel*> channels_;
map<string, GVariant*> options_;
};
#include <pv/data/decode/row.hpp>
#include <pv/session.hpp>
-using boost::optional;
using std::lock_guard;
using std::make_pair;
using std::make_shared;
logic_mux_data_invalid_(false),
start_time_(0),
samplerate_(0),
- sample_count_(0),
annotation_count_(0),
samples_decoded_(0),
frame_complete_(false)
if (stack_.size() == 1)
set_name(QString::fromUtf8(decoder->name));
- // Include the newly created decode channels in the channel list
+ // Include the newly created decode channels in the channel lists
update_channel_list();
auto_assign_signals();
+ commit_decoder_channels();
begin_decode();
}
void DecodeSignal::reset_decode()
{
- sample_count_ = 0;
annotation_count_ = 0;
frame_complete_ = false;
samples_decoded_ = 0;
reset_decode();
+ if (stack_.size() == 0) {
+ error_message_ = tr("No decoders");
+ return;
+ }
+
+ assert(channels_.size() > 0);
+
+ if (get_assigned_signal_count() == 0) {
+ error_message_ = tr("There are no channels assigned to this decoder");
+ return;
+ }
+
// Check that all decoders have the required channels
for (const shared_ptr<decode::Decoder> &dec : stack_)
if (!dec->have_required_channels()) {
}
}
- // Make sure the logic output data is complete and up-to-date
- logic_mux_thread_ = std::thread(&DecodeSignal::logic_mux_proc, this);
+ // TODO Currently we assume all channels have the same sample rate
+ auto any_channel = find_if(channels_.begin(), channels_.end(),
+ [](data::DecodeChannel ch) { return ch.assigned_signal; });
+ shared_ptr<LogicSegment> first_segment =
+ any_channel->assigned_signal->logic_data()->logic_segments().front();
+ samplerate_ = first_segment->samplerate();
+
+ // Free the logic data and its segment(s) if it needs to be updated
+ if (logic_mux_data_invalid_)
+ logic_mux_data_.reset();
+
+ if (!logic_mux_data_) {
+ const int64_t ch_count = get_assigned_signal_count();
+ const int64_t unit_size = (ch_count + 7) / 8;
+ logic_mux_data_ = make_shared<Logic>(ch_count);
+ segment_ = make_shared<LogicSegment>(*logic_mux_data_, unit_size, samplerate_);
+ logic_mux_data_->push_segment(segment_);
+ }
// Update the samplerate and start time
start_time_ = segment_->start_time();
if (samplerate_ == 0.0)
samplerate_ = 1.0;
+ // Make sure the logic output data is complete and up-to-date
+ logic_mux_interrupt_ = false;
+ logic_mux_thread_ = std::thread(&DecodeSignal::logic_mux_proc, this);
+
+ // Decode the muxed logic data
decode_interrupt_ = false;
decode_thread_ = std::thread(&DecodeSignal::decode_proc, this);
}
if (new_assignment) {
logic_mux_data_invalid_ = true;
+ commit_decoder_channels();
channels_updated();
}
}
logic_mux_data_invalid_ = true;
}
+ commit_decoder_channels();
channels_updated();
-
begin_decode();
}
+int DecodeSignal::get_assigned_signal_count() const
+{
+ // Count all channels that have a signal assigned to them
+ return count_if(channels_.begin(), channels_.end(),
+ [](data::DecodeChannel ch) { return ch.assigned_signal; });
+}
+
void DecodeSignal::set_initial_pin_state(const uint16_t channel_id, const int init_state)
{
for (data::DecodeChannel &ch : channels_)
channels_updated();
}
-void DecodeSignal::logic_mux_proc()
+void DecodeSignal::commit_decoder_channels()
{
+ // Submit channel list to every decoder, containing only the relevant channels
+ for (shared_ptr<decode::Decoder> dec : stack_) {
+ vector<data::DecodeChannel*> channel_list;
+ for (data::DecodeChannel &ch : channels_)
+ if (ch.decoder_ == dec)
+ channel_list.push_back(&ch);
+
+ dec->set_channels(channel_list);
+ }
}
-optional<int64_t> DecodeSignal::wait_for_data() const
+void DecodeSignal::mux_logic_samples(const int64_t start, const int64_t end)
{
- unique_lock<mutex> input_lock(input_mutex_);
+ // Enforce end to be greater than start
+ if (end <= start)
+ return;
+
+ // Fetch all segments and their data
+ // TODO Currently, we assume only a single segment exists
+ vector<shared_ptr<LogicSegment> > segments;
+ vector<const uint8_t*> signal_data;
+ vector<uint8_t> signal_in_bytepos;
+ vector<uint8_t> signal_in_bitpos;
+
+ for (data::DecodeChannel &ch : channels_)
+ if (ch.assigned_signal) {
+ const shared_ptr<Logic> logic_data = ch.assigned_signal->logic_data();
+ const shared_ptr<LogicSegment> segment = logic_data->logic_segments().front();
+ segments.push_back(segment);
+ signal_data.push_back(segment->get_samples(start, end));
+
+ const int bitpos = ch.assigned_signal->logic_bit_index();
+ signal_in_bytepos.push_back(bitpos / 8);
+ signal_in_bitpos.push_back(bitpos % 8);
+ }
+
+ // Perform the muxing of signal data into the output data
+ uint8_t* output = new uint8_t[(end - start) * segment_->unit_size()];
+ unsigned int signal_count = signal_data.size();
- // Do wait if we decoded all samples but we're still capturing
- // Do not wait if we're done capturing
- while (!decode_interrupt_ && !frame_complete_ &&
- (samples_decoded_ >= sample_count_) &&
- (session_.get_capture_state() != Session::Stopped)) {
+ for (int64_t sample_cnt = 0; sample_cnt < (end - start); sample_cnt++) {
+ int bitpos = 0;
+ uint8_t bytepos = 0;
- decode_input_cond_.wait(input_lock);
+ const int out_sample_pos = sample_cnt * segment_->unit_size();
+ for (unsigned int i = 0; i < segment_->unit_size(); i++)
+ output[out_sample_pos + i] = 0;
+
+ for (unsigned int i = 0; i < signal_count; i++) {
+ const int in_sample_pos = sample_cnt * segments[i]->unit_size();
+ const uint8_t in_sample = 1 &
+ ((signal_data[i][in_sample_pos + signal_in_bytepos[i]]) >> (signal_in_bitpos[i]));
+
+ const uint8_t out_sample = output[out_sample_pos + bytepos];
+
+ output[out_sample_pos + bytepos] = out_sample | (in_sample << bitpos);
+
+ bitpos++;
+ if (bitpos > 7) {
+ bitpos = 0;
+ bytepos++;
+ }
+ }
}
- // Return value is valid if we're not aborting the decode,
- return boost::make_optional(!decode_interrupt_ &&
- // and there's more work to do...
- (samples_decoded_ < sample_count_ || !frame_complete_) &&
- // and if the end of the data hasn't been reached yet
- (!((samples_decoded_ >= sample_count_) && (session_.get_capture_state() == Session::Stopped))),
- sample_count_);
+ segment_->append_payload(output, (end - start) * segment_->unit_size());
+ delete[] output;
+
+ for (const uint8_t* data : signal_data)
+ delete[] data;
+}
+
+void DecodeSignal::logic_mux_proc()
+{
+ do {
+
+ const uint64_t input_sample_count = get_working_sample_count();
+ const uint64_t output_sample_count = segment_->get_sample_count();
+
+ const uint64_t samples_to_process =
+ (input_sample_count > output_sample_count) ?
+ (input_sample_count - output_sample_count) : 0;
+
+ // Process the samples if necessary...
+ if (samples_to_process > 0) {
+ const uint64_t unit_size = segment_->unit_size();
+ const uint64_t chunk_sample_count = DecodeChunkLength / unit_size;
+
+ uint64_t processed_samples = 0;
+ do {
+ const uint64_t start_sample = output_sample_count + processed_samples;
+ const uint64_t sample_count =
+ min(samples_to_process - processed_samples, chunk_sample_count);
+
+ mux_logic_samples(start_sample, start_sample + sample_count);
+ processed_samples += sample_count;
+
+ // ...and process the newly muxed logic data
+ decode_input_cond_.notify_one();
+ } while (processed_samples < samples_to_process);
+ }
+
+ if (session_.get_capture_state() != Session::Stopped) {
+ // Wait for more input
+ unique_lock<mutex> logic_mux_lock(logic_mux_mutex_);
+ logic_mux_cond_.wait(logic_mux_lock);
+ }
+ } while ((session_.get_capture_state() != Session::Stopped) && !logic_mux_interrupt_);
+
+ // No more input data and session is stopped, let the decode thread
+ // process any pending data, terminate and release the global SRD mutex
+ // in order to let other decoders run
+ decode_input_cond_.notify_one();
}
void DecodeSignal::decode_data(
const int64_t abs_start_samplenum, const int64_t sample_count,
srd_session *const session)
{
- const unsigned int unit_size = segment_->unit_size();
- const unsigned int chunk_sample_count = DecodeChunkLength / unit_size;
+ const int64_t unit_size = segment_->unit_size();
+ const int64_t chunk_sample_count = DecodeChunkLength / unit_size;
for (int64_t i = abs_start_samplenum;
!decode_interrupt_ && (i < (abs_start_samplenum + sample_count));
void DecodeSignal::decode_proc()
{
- optional<int64_t> sample_count;
srd_session *session;
srd_decoder_inst *prev_di = nullptr;
prev_di = di;
}
- // Get the initial sample count
- {
- unique_lock<mutex> input_lock(input_mutex_);
- sample_count = sample_count_ = get_working_sample_count();
- }
-
// Start the session
srd_session_metadata_set(session, SRD_CONF_SAMPLERATE,
g_variant_new_uint64(samplerate_));
srd_session_start(session);
- int64_t abs_start_samplenum = 0;
+ uint64_t sample_count;
+ uint64_t abs_start_samplenum = 0;
do {
- decode_data(abs_start_samplenum, *sample_count, session);
- abs_start_samplenum = *sample_count;
- } while (error_message_.isEmpty() && (sample_count = wait_for_data()));
+ // Keep processing new samples until we exhaust the input data
+ do {
+ {
+ lock_guard<mutex> input_lock(input_mutex_);
+ sample_count = segment_->get_sample_count() - abs_start_samplenum;
+ }
+
+ if (sample_count > 0) {
+ decode_data(abs_start_samplenum, sample_count, session);
+ abs_start_samplenum += sample_count;
+ }
+ } while (error_message_.isEmpty() && (sample_count > 0));
+
+ // Terminate if we exhausted the input data
+ if ((int64_t)segment_->get_sample_count() == get_working_sample_count())
+ break;
+
+ if (error_message_.isEmpty()) {
+ // Wait for new input data or an interrupt request
+ unique_lock<mutex> input_wait_lock(input_mutex_);
+ decode_input_cond_.wait(input_wait_lock);
+ }
+ } while (error_message_.isEmpty() && !decode_interrupt_);
// Make sure all annotations are known to the frontend
new_annotations();
#include <unordered_set>
#include <vector>
-#include <boost/optional.hpp>
-
#include <QSettings>
#include <QString>
const vector<data::DecodeChannel> get_channels() const;
void auto_assign_signals();
void assign_signal(const uint16_t channel_id, const SignalBase *signal);
+ int get_assigned_signal_count() const;
void set_initial_pin_state(const uint16_t channel_id, const int init_state);
private:
void update_channel_list();
- void logic_mux_proc();
+ void commit_decoder_channels();
- boost::optional<int64_t> wait_for_data() const;
+ void mux_logic_samples(const int64_t start, const int64_t end);
+
+ void logic_mux_proc();
void decode_data(const int64_t abs_start_samplenum, const int64_t sample_count,
srd_session *const session);
pv::util::Timestamp start_time_;
double samplerate_;
- int64_t sample_count_, annotation_count_, samples_decoded_;
+ int64_t annotation_count_, samples_decoded_;
vector< shared_ptr<decode::Decoder> > stack_;
map<const decode::Row, decode::RowData> rows_;
*/
static mutex global_srd_mutex_;
- mutable mutex input_mutex_, output_mutex_;
+ mutable mutex input_mutex_, output_mutex_, logic_mux_mutex_;
mutable condition_variable decode_input_cond_, logic_mux_cond_;
bool frame_complete_;
using std::make_shared;
using std::shared_ptr;
using std::tie;
+using std::unique_lock;
namespace pv {
namespace data {
SignalBase::~SignalBase()
{
- // Wait for the currently ongoing conversion to finish
- if (conversion_thread_.joinable())
- conversion_thread_.join();
+ stop_conversion();
}
shared_ptr<sigrok::Channel> SignalBase::channel() const
unsigned int SignalBase::index() const
{
- return (channel_) ? channel_->index() : (unsigned int)-1;
+ return (channel_) ? channel_->index() : 0;
+}
+
+unsigned int SignalBase::logic_bit_index() const
+{
+ if (channel_type_ == LogicChannel)
+ return channel_->index();
+ else
+ return 0;
}
QColor SignalBase::colour() const
void SignalBase::set_conversion_type(ConversionType t)
{
if (conversion_type_ != NoConversion) {
- // Wait for the currently ongoing conversion to finish
- if (conversion_thread_.joinable())
- conversion_thread_.join();
+ stop_conversion();
// Discard converted data
converted_data_.reset();
conversion_type_ = t;
- if ((channel_type_ == AnalogChannel) &&
- ((conversion_type_ == A2LConversionByTreshold) ||
- (conversion_type_ == A2LConversionBySchmittTrigger))) {
-
- shared_ptr<Analog> analog_data = dynamic_pointer_cast<Analog>(data_);
-
- if (analog_data->analog_segments().size() > 0) {
- AnalogSegment *asegment = analog_data->analog_segments().front().get();
-
- // Begin conversion of existing sample data
- // TODO Support for multiple segments is missing
- on_samples_added(asegment, 0, 0);
- }
- }
+ start_conversion();
conversion_type_changed(t);
}
return state;
}
-void SignalBase::conversion_thread_proc(QObject* segment, uint64_t start_sample,
- uint64_t end_sample)
+void SignalBase::conversion_thread_proc(QObject* segment)
{
// TODO Support for multiple segments is missing
- if ((channel_type_ == AnalogChannel) &&
- ((conversion_type_ == A2LConversionByTreshold) ||
- (conversion_type_ == A2LConversionBySchmittTrigger))) {
+ uint64_t start_sample, end_sample;
+ start_sample = end_sample = 0;
- AnalogSegment *asegment = qobject_cast<AnalogSegment*>(segment);
-
- // Create the logic data container if needed
- shared_ptr<Logic> logic_data;
- if (!converted_data_) {
- logic_data = make_shared<Logic>(1); // Contains only one channel
- converted_data_ = logic_data;
- } else
- logic_data = dynamic_pointer_cast<Logic>(converted_data_);
-
- // Create the initial logic data segment if needed
- if (logic_data->segments().size() == 0) {
- shared_ptr<LogicSegment> lsegment =
- make_shared<LogicSegment>(*logic_data.get(), 1, asegment->samplerate());
- logic_data->push_segment(lsegment);
- }
+ do {
+ if ((channel_type_ == AnalogChannel) &&
+ ((conversion_type_ == A2LConversionByTreshold) ||
+ (conversion_type_ == A2LConversionBySchmittTrigger))) {
+
+ AnalogSegment *asegment = qobject_cast<AnalogSegment*>(segment);
+
+ // Create the logic data container if needed
+ shared_ptr<Logic> logic_data;
+ if (!converted_data_) {
+ logic_data = make_shared<Logic>(1); // Contains only one channel
+ converted_data_ = logic_data;
+ } else
+ logic_data = dynamic_pointer_cast<Logic>(converted_data_);
+
+ // Create the initial logic data segment if needed
+ if (logic_data->segments().size() == 0) {
+ shared_ptr<LogicSegment> lsegment =
+ make_shared<LogicSegment>(*logic_data.get(), 1, asegment->samplerate());
+ logic_data->push_segment(lsegment);
+ }
- LogicSegment *lsegment = dynamic_cast<LogicSegment*>(logic_data->segments().front().get());
+ LogicSegment *lsegment = dynamic_cast<LogicSegment*>(logic_data->segments().front().get());
- // start_sample=end_sample=0 means we need to figure out the unprocessed range
- if ((start_sample == 0) && (end_sample == 0)) {
start_sample = lsegment->get_sample_count();
end_sample = asegment->get_sample_count();
- }
-
- if (start_sample == end_sample)
- return; // Nothing to do
-
- float min_v, max_v;
- tie(min_v, max_v) = asegment->get_min_max();
-
- vector<uint8_t> lsamples;
- lsamples.reserve(ConversionBlockSize);
-
- uint64_t i = start_sample;
- if (conversion_type_ == A2LConversionByTreshold) {
- const float threshold = (min_v + max_v) * 0.5; // middle between min and max
-
- // Convert as many sample blocks as we can
- while ((end_sample - i) > ConversionBlockSize) {
- const float* asamples = asegment->get_samples(i, i + ConversionBlockSize);
- for (uint32_t j = 0; j < ConversionBlockSize; j++)
- lsamples.push_back(convert_a2l_threshold(threshold, asamples[j]));
- lsegment->append_payload(lsamples.data(), lsamples.size());
- i += ConversionBlockSize;
- lsamples.clear();
- delete[] asamples;
+ if (end_sample > start_sample) {
+ float min_v, max_v;
+ tie(min_v, max_v) = asegment->get_min_max();
+
+ vector<uint8_t> lsamples;
+ lsamples.reserve(ConversionBlockSize);
+
+ uint64_t i = start_sample;
+
+ if (conversion_type_ == A2LConversionByTreshold) {
+ const float threshold = (min_v + max_v) * 0.5; // middle between min and max
+
+ // Convert as many sample blocks as we can
+ while ((end_sample - i) > ConversionBlockSize) {
+ const float* asamples = asegment->get_samples(i, i + ConversionBlockSize);
+ for (uint32_t j = 0; j < ConversionBlockSize; j++)
+ lsamples.push_back(convert_a2l_threshold(threshold, asamples[j]));
+ lsegment->append_payload(lsamples.data(), lsamples.size());
+ samples_added(lsegment, i, i + ConversionBlockSize);
+ i += ConversionBlockSize;
+ lsamples.clear();
+ delete[] asamples;
+ }
+
+ // Convert remaining samples
+ const float* asamples = asegment->get_samples(i, end_sample);
+ for (uint32_t j = 0; j < (end_sample - i); j++)
+ lsamples.push_back(convert_a2l_threshold(threshold, asamples[j]));
+ lsegment->append_payload(lsamples.data(), lsamples.size());
+ samples_added(lsegment, i, end_sample);
+ delete[] asamples;
+ }
+
+ if (conversion_type_ == A2LConversionBySchmittTrigger) {
+ const float amplitude = max_v - min_v;
+ const float lo_thr = min_v + (amplitude * 0.1); // 10% above min
+ const float hi_thr = max_v - (amplitude * 0.1); // 10% below max
+ uint8_t state = 0; // TODO Use value of logic sample n-1 instead of 0
+
+ // Convert as many sample blocks as we can
+ while ((end_sample - i) > ConversionBlockSize) {
+ const float* asamples = asegment->get_samples(i, i + ConversionBlockSize);
+ for (uint32_t j = 0; j < ConversionBlockSize; j++)
+ lsamples.push_back(convert_a2l_schmitt_trigger(lo_thr, hi_thr, asamples[j], state));
+ lsegment->append_payload(lsamples.data(), lsamples.size());
+ samples_added(lsegment, i, i + ConversionBlockSize);
+ i += ConversionBlockSize;
+ lsamples.clear();
+ delete[] asamples;
+ }
+
+ // Convert remaining samples
+ const float* asamples = asegment->get_samples(i, end_sample);
+ for (uint32_t j = 0; j < (end_sample - i); j++)
+ lsamples.push_back(convert_a2l_schmitt_trigger(lo_thr, hi_thr, asamples[j], state));
+ lsegment->append_payload(lsamples.data(), lsamples.size());
+ samples_added(lsegment, i, end_sample);
+ delete[] asamples;
+ }
+
+ // If acquisition is ongoing, start-/endsample may have changed
+ end_sample = asegment->get_sample_count();
}
+ }
- // Convert remaining samples
- const float* asamples = asegment->get_samples(i, end_sample);
- for (uint32_t j = 0; j < (end_sample - i); j++)
- lsamples.push_back(convert_a2l_threshold(threshold, asamples[j]));
- lsegment->append_payload(lsamples.data(), lsamples.size());
- delete[] asamples;
-
- samples_added(lsegment, start_sample, end_sample);
+ if (!conversion_interrupt_ && (start_sample == end_sample)) {
+ unique_lock<mutex> input_lock(conversion_input_mutex_);
+ conversion_input_cond_.wait(input_lock);
}
+ } while (!conversion_interrupt_);
+}
- if (conversion_type_ == A2LConversionBySchmittTrigger) {
- const float amplitude = max_v - min_v;
- const float lo_thr = min_v + (amplitude * 0.1); // 10% above min
- const float hi_thr = max_v - (amplitude * 0.1); // 10% below max
- uint8_t state = 0; // TODO Use value of logic sample n-1 instead of 0
-
- // Convert as many sample blocks as we can
- while ((end_sample - i) > ConversionBlockSize) {
- const float* asamples = asegment->get_samples(i, i + ConversionBlockSize);
- for (uint32_t j = 0; j < ConversionBlockSize; j++)
- lsamples.push_back(convert_a2l_schmitt_trigger(lo_thr, hi_thr, asamples[j], state));
- lsegment->append_payload(lsamples.data(), lsamples.size());
- i += ConversionBlockSize;
- lsamples.clear();
- delete[] asamples;
- }
+void SignalBase::start_conversion()
+{
+ stop_conversion();
+
+ if ((channel_type_ == AnalogChannel) &&
+ ((conversion_type_ == A2LConversionByTreshold) ||
+ (conversion_type_ == A2LConversionBySchmittTrigger))) {
+
+ shared_ptr<Analog> analog_data = dynamic_pointer_cast<Analog>(data_);
- // Convert remaining samples
- const float* asamples = asegment->get_samples(i, end_sample);
- for (uint32_t j = 0; j < (end_sample - i); j++)
- lsamples.push_back(convert_a2l_schmitt_trigger(lo_thr, hi_thr, asamples[j], state));
- lsegment->append_payload(lsamples.data(), lsamples.size());
- delete[] asamples;
+ if (analog_data->analog_segments().size() > 0) {
+ // TODO Support for multiple segments is missing
+ AnalogSegment *asegment = analog_data->analog_segments().front().get();
- samples_added(lsegment, start_sample, end_sample);
+ conversion_interrupt_ = false;
+ conversion_thread_ = std::thread(
+ &SignalBase::conversion_thread_proc, this, asegment);
}
}
}
+void SignalBase::stop_conversion()
+{
+ // Stop conversion so we can restart it from the beginning
+ conversion_interrupt_ = true;
+ conversion_input_cond_.notify_one();
+ if (conversion_thread_.joinable())
+ conversion_thread_.join();
+}
+
void SignalBase::on_samples_cleared()
{
if (converted_data_)
uint64_t end_sample)
{
if (conversion_type_ != NoConversion) {
-
- // Wait for the currently ongoing conversion to finish
- if (conversion_thread_.joinable())
- conversion_thread_.join();
-
- conversion_thread_ = std::thread(
- &SignalBase::conversion_thread_proc, this,
- segment, start_sample, end_sample);
+ if (conversion_thread_.joinable()) {
+ // Notify the conversion thread since it's running
+ conversion_input_cond_.notify_one();
+ } else {
+ // Start the conversion thread
+ start_conversion();
+ }
}
samples_added(segment, start_sample, end_sample);
void SignalBase::on_capture_state_changed(int state)
{
- return;
- if (state == Session::Stopped) {
- // Make sure that all data is converted
-
- if ((channel_type_ == AnalogChannel) &&
- ((conversion_type_ == A2LConversionByTreshold) ||
- (conversion_type_ == A2LConversionBySchmittTrigger))) {
-
- shared_ptr<Analog> analog_data = dynamic_pointer_cast<Analog>(data_);
-
- if (analog_data->analog_segments().size() > 0) {
- // TODO Support for multiple segments is missing
- AnalogSegment *asegment = analog_data->analog_segments().front().get();
-
- if (conversion_thread_.joinable())
- conversion_thread_.join();
-
- conversion_thread_ = std::thread(
- &SignalBase::conversion_thread_proc, this, asegment, 0, 0);
- }
+ if (state == Session::Running) {
+ if (conversion_type_ != NoConversion) {
+ // Restart conversion
+ stop_conversion();
+ start_conversion();
}
}
}
#ifndef PULSEVIEW_PV_DATA_SIGNALBASE_HPP
#define PULSEVIEW_PV_DATA_SIGNALBASE_HPP
+#include <atomic>
+#include <condition_variable>
#include <thread>
#include <QColor>
#include <libsigrokcxx/libsigrokcxx.hpp>
+using std::atomic;
+using std::condition_variable;
+using std::mutex;
using std::shared_ptr;
namespace sigrok {
ChannelType type() const;
/**
- * Gets the index number of this channel.
+ * Gets the index number of this channel, i.e. a unique ID assigned by
+ * the device driver.
*/
unsigned int index() const;
+ /**
+ * Returns which bit of a given sample for this signal represents the
+ * signal itself. This is relevant for compound signals like logic,
+ * rather meaningless for everything else but provided in case there
+ * is a conversion active that provides a digital signal using bit #0.
+ */
+ unsigned int logic_bit_index() const;
+
/**
* Gets the name of this signal.
*/
uint8_t convert_a2l_schmitt_trigger(float lo_thr, float hi_thr,
float value, uint8_t &state);
- void conversion_thread_proc(QObject* segment, uint64_t start_sample,
- uint64_t end_sample);
+ void conversion_thread_proc(QObject* segment);
+
+ void start_conversion();
+ void stop_conversion();
Q_SIGNALS:
void enabled_changed(const bool &value);
int conversion_type_;
std::thread conversion_thread_;
+ atomic<bool> conversion_interrupt_;
+ mutex conversion_input_mutex_;
+ condition_variable conversion_input_cond_;
QString internal_name_, name_;
QColor colour_, bgcolour_;