mirror of git://sigrok.org/pulseview
Prepare multi-segment protocol decoding ability
This commit is contained in:
parent
ba5f21864c
commit
72435789a0
|
@ -56,10 +56,8 @@ DecodeSignal::DecodeSignal(pv::Session &session) :
|
|||
session_(session),
|
||||
srd_session_(nullptr),
|
||||
logic_mux_data_invalid_(false),
|
||||
start_time_(0),
|
||||
samplerate_(0),
|
||||
samples_decoded_(0),
|
||||
frame_complete_(false)
|
||||
current_segment_id_(0),
|
||||
current_segment_(nullptr)
|
||||
{
|
||||
connect(&session_, SIGNAL(capture_state_changed(int)),
|
||||
this, SLOT(on_capture_state_changed(int)));
|
||||
|
@ -146,18 +144,16 @@ void DecodeSignal::reset_decode()
|
|||
|
||||
stop_srd_session();
|
||||
|
||||
frame_complete_ = false;
|
||||
samples_decoded_ = 0;
|
||||
currently_processed_segment_ = 0;
|
||||
error_message_ = QString();
|
||||
|
||||
segmented_rows_.clear();
|
||||
current_rows_= nullptr;
|
||||
class_rows_.clear();
|
||||
currently_processed_segment_ = 0;
|
||||
current_segment_ = nullptr;
|
||||
segments_.clear();
|
||||
|
||||
logic_mux_data_.reset();
|
||||
logic_mux_data_invalid_ = true;
|
||||
|
||||
error_message_ = QString();
|
||||
|
||||
decode_reset();
|
||||
}
|
||||
|
||||
|
@ -224,22 +220,18 @@ void DecodeSignal::begin_decode()
|
|||
}
|
||||
}
|
||||
|
||||
create_new_annotation_segment();
|
||||
|
||||
// TODO Allow logic_mux_data and logic_mux_segment to work with multiple segments
|
||||
|
||||
// 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;
|
||||
const uint32_t ch_count = get_assigned_signal_count();
|
||||
logic_unit_size_ = (ch_count + 7) / 8;
|
||||
logic_mux_data_ = make_shared<Logic>(ch_count);
|
||||
logic_mux_segment_ = make_shared<LogicSegment>(*logic_mux_data_, unit_size, samplerate_);
|
||||
logic_mux_data_->push_segment(logic_mux_segment_);
|
||||
}
|
||||
|
||||
create_new_segment();
|
||||
|
||||
// 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);
|
||||
|
@ -328,12 +320,32 @@ void DecodeSignal::set_initial_pin_state(const uint16_t channel_id, const int in
|
|||
|
||||
double DecodeSignal::samplerate() const
|
||||
{
|
||||
return samplerate_;
|
||||
double result = 0;
|
||||
|
||||
// TODO For now, we simply return the first samplerate that we have
|
||||
try {
|
||||
const DecodeSegment *segment = &(segments_.at(0));
|
||||
result = segment->samplerate;
|
||||
} catch (out_of_range) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const pv::util::Timestamp& DecodeSignal::start_time() const
|
||||
const pv::util::Timestamp DecodeSignal::start_time() const
|
||||
{
|
||||
return start_time_;
|
||||
pv::util::Timestamp result;
|
||||
|
||||
// TODO For now, we simply return the first start time that we have
|
||||
try {
|
||||
const DecodeSegment *segment = &(segments_.at(0));
|
||||
result = segment->start_time;
|
||||
} catch (out_of_range) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t DecodeSignal::get_working_sample_count(uint32_t segment_id) const
|
||||
|
@ -371,15 +383,12 @@ int64_t DecodeSignal::get_decoded_sample_count(uint32_t segment_id) const
|
|||
|
||||
int64_t result = 0;
|
||||
|
||||
if (segment_id == currently_processed_segment_)
|
||||
result = samples_decoded_;
|
||||
else
|
||||
if (segment_id < currently_processed_segment_)
|
||||
// Segment was already decoded fully
|
||||
result = get_working_sample_count(segment_id);
|
||||
else
|
||||
// Segment wasn't decoded at all yet
|
||||
result = 0;
|
||||
try {
|
||||
const DecodeSegment *segment = &(segments_.at(segment_id));
|
||||
result = segment->samples_decoded;
|
||||
} catch (out_of_range) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -416,20 +425,23 @@ vector<Row> DecodeSignal::visible_rows() const
|
|||
|
||||
void DecodeSignal::get_annotation_subset(
|
||||
vector<pv::data::decode::Annotation> &dest,
|
||||
const decode::Row &row, uint64_t start_sample,
|
||||
const decode::Row &row, uint32_t segment_id, uint64_t start_sample,
|
||||
uint64_t end_sample) const
|
||||
{
|
||||
lock_guard<mutex> lock(output_mutex_);
|
||||
|
||||
if (!current_rows_)
|
||||
return;
|
||||
try {
|
||||
const DecodeSegment *segment = &(segments_.at(segment_id));
|
||||
const map<const decode::Row, decode::RowData> *rows =
|
||||
&(segment->annotation_rows);
|
||||
|
||||
// TODO Instead of current_rows_, use segmented_rows_ and the ID of the segment
|
||||
|
||||
const auto iter = current_rows_->find(row);
|
||||
if (iter != current_rows_->end())
|
||||
(*iter).second.get_annotation_subset(dest,
|
||||
start_sample, end_sample);
|
||||
const auto iter = rows->find(row);
|
||||
if (iter != rows->end())
|
||||
(*iter).second.get_annotation_subset(dest,
|
||||
start_sample, end_sample);
|
||||
} catch (out_of_range) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeSignal::save_settings(QSettings &settings) const
|
||||
|
@ -784,6 +796,8 @@ void DecodeSignal::query_input_metadata()
|
|||
data::DecodeChannel *any_channel;
|
||||
shared_ptr<Logic> logic_data;
|
||||
|
||||
assert(current_segment_);
|
||||
|
||||
do {
|
||||
any_channel = &(*find_if(channels_.begin(), channels_.end(),
|
||||
[](data::DecodeChannel ch) { return ch.assigned_signal; }));
|
||||
|
@ -804,9 +818,10 @@ void DecodeSignal::query_input_metadata()
|
|||
if (!logic_data->logic_segments().empty()) {
|
||||
shared_ptr<LogicSegment> first_segment =
|
||||
any_channel->assigned_signal->logic_data()->logic_segments().front();
|
||||
start_time_ = first_segment->start_time();
|
||||
samplerate_ = first_segment->samplerate();
|
||||
if (samplerate_ > 0)
|
||||
|
||||
current_segment_->start_time = first_segment->start_time();
|
||||
current_segment_->samplerate = first_segment->samplerate();
|
||||
if (current_segment_->samplerate > 0)
|
||||
samplerate_valid = true;
|
||||
}
|
||||
|
||||
|
@ -821,6 +836,8 @@ void DecodeSignal::query_input_metadata()
|
|||
void DecodeSignal::decode_data(
|
||||
const int64_t abs_start_samplenum, const int64_t sample_count)
|
||||
{
|
||||
assert(current_segment_);
|
||||
|
||||
const int64_t unit_size = logic_mux_segment_->unit_size();
|
||||
const int64_t chunk_sample_count = DecodeChunkLength / unit_size;
|
||||
|
||||
|
@ -846,7 +863,7 @@ void DecodeSignal::decode_data(
|
|||
|
||||
{
|
||||
lock_guard<mutex> lock(output_mutex_);
|
||||
samples_decoded_ = chunk_end;
|
||||
current_segment_->samples_decoded = chunk_end;
|
||||
}
|
||||
|
||||
// Notify the frontend that we processed some data and
|
||||
|
@ -894,6 +911,8 @@ void DecodeSignal::start_srd_session()
|
|||
if (srd_session_)
|
||||
stop_srd_session();
|
||||
|
||||
assert(current_segment_);
|
||||
|
||||
// Create the session
|
||||
srd_session_new(&srd_session_);
|
||||
assert(srd_session_);
|
||||
|
@ -917,7 +936,7 @@ void DecodeSignal::start_srd_session()
|
|||
|
||||
// Start the session
|
||||
srd_session_metadata_set(srd_session_, SRD_CONF_SAMPLERATE,
|
||||
g_variant_new_uint64(samplerate_));
|
||||
g_variant_new_uint64(current_segment_->samplerate));
|
||||
|
||||
srd_pd_output_callback_add(srd_session_, SRD_OUTPUT_ANN,
|
||||
DecodeSignal::annotation_callback, this);
|
||||
|
@ -953,10 +972,24 @@ void DecodeSignal::connect_input_notifiers()
|
|||
}
|
||||
}
|
||||
|
||||
void DecodeSignal::create_new_annotation_segment()
|
||||
void DecodeSignal::create_new_segment()
|
||||
{
|
||||
segmented_rows_.emplace_back(map<const decode::Row, decode::RowData>());
|
||||
current_rows_ = &(segmented_rows_.back());
|
||||
// Create logic mux segment if we're recreating the muxed data
|
||||
if (logic_mux_data_invalid_) {
|
||||
const double samplerate =
|
||||
(current_segment_) ? current_segment_->samplerate : 0;
|
||||
|
||||
logic_mux_segment_ = make_shared<LogicSegment>(*logic_mux_data_,
|
||||
logic_unit_size_, samplerate);
|
||||
logic_mux_data_->push_segment(logic_mux_segment_);
|
||||
}
|
||||
|
||||
// Create annotation segment
|
||||
segments_.emplace_back(DecodeSegment());
|
||||
current_segment_ = &(segments_.back());
|
||||
|
||||
// TODO Currently we assume there's only one sample rate
|
||||
current_segment_->samplerate = segments_.front().samplerate;
|
||||
|
||||
// Add annotation classes
|
||||
for (const shared_ptr<decode::Decoder> &dec : stack_) {
|
||||
|
@ -966,7 +999,7 @@ void DecodeSignal::create_new_annotation_segment()
|
|||
|
||||
// Add a row for the decoder if it doesn't have a row list
|
||||
if (!decc->annotation_rows)
|
||||
(*current_rows_)[Row(decc)] = decode::RowData();
|
||||
(current_segment_->annotation_rows)[Row(decc)] = decode::RowData();
|
||||
|
||||
// Add the decoder rows
|
||||
for (const GSList *l = decc->annotation_rows; l; l = l->next) {
|
||||
|
@ -977,7 +1010,7 @@ void DecodeSignal::create_new_annotation_segment()
|
|||
const Row row(decc, ann_row);
|
||||
|
||||
// Add a new empty row data object
|
||||
(*current_rows_)[row] = decode::RowData();
|
||||
(current_segment_->annotation_rows)[row] = decode::RowData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -997,25 +1030,25 @@ void DecodeSignal::annotation_callback(srd_proto_data *pdata, void *decode_signa
|
|||
assert(pdata->pdo->di);
|
||||
const srd_decoder *const decc = pdata->pdo->di->decoder;
|
||||
assert(decc);
|
||||
assert(ds->current_rows_);
|
||||
assert(ds->current_segment_);
|
||||
|
||||
const srd_proto_data_annotation *const pda =
|
||||
(const srd_proto_data_annotation*)pdata->data;
|
||||
assert(pda);
|
||||
|
||||
auto row_iter = ds->current_rows_->end();
|
||||
auto row_iter = ds->current_segment_->annotation_rows.end();
|
||||
|
||||
// Try looking up the sub-row of this class
|
||||
const auto format = pda->ann_class;
|
||||
const auto r = ds->class_rows_.find(make_pair(decc, format));
|
||||
if (r != ds->class_rows_.end())
|
||||
row_iter = ds->current_rows_->find((*r).second);
|
||||
row_iter = ds->current_segment_->annotation_rows.find((*r).second);
|
||||
else {
|
||||
// Failing that, use the decoder as a key
|
||||
row_iter = ds->current_rows_->find(Row(decc));
|
||||
row_iter = ds->current_segment_->annotation_rows.find(Row(decc));
|
||||
}
|
||||
|
||||
if (row_iter == ds->current_rows_->end()) {
|
||||
if (row_iter == ds->current_segment_->annotation_rows.end()) {
|
||||
qDebug() << "Unexpected annotation: decoder = " << decc <<
|
||||
", format = " << format;
|
||||
assert(false);
|
||||
|
|
|
@ -71,6 +71,14 @@ struct DecodeChannel
|
|||
const srd_channel *pdch_;
|
||||
};
|
||||
|
||||
struct DecodeSegment
|
||||
{
|
||||
map<const decode::Row, decode::RowData> annotation_rows;
|
||||
pv::util::Timestamp start_time;
|
||||
double samplerate;
|
||||
int64_t samples_decoded;
|
||||
};
|
||||
|
||||
class DecodeSignal : public SignalBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -103,7 +111,7 @@ public:
|
|||
void set_initial_pin_state(const uint16_t channel_id, const int init_state);
|
||||
|
||||
double samplerate() const;
|
||||
const pv::util::Timestamp& start_time() const;
|
||||
const pv::util::Timestamp start_time() const;
|
||||
|
||||
/**
|
||||
* Returns the number of samples that can be worked on,
|
||||
|
@ -121,7 +129,7 @@ public:
|
|||
*/
|
||||
void get_annotation_subset(
|
||||
vector<pv::data::decode::Annotation> &dest,
|
||||
const decode::Row &row, uint64_t start_sample,
|
||||
const decode::Row &row, uint32_t segment_id, uint64_t start_sample,
|
||||
uint64_t end_sample) const;
|
||||
|
||||
virtual void save_settings(QSettings &settings) const;
|
||||
|
@ -148,7 +156,8 @@ private:
|
|||
|
||||
void connect_input_notifiers();
|
||||
|
||||
void create_new_annotation_segment();
|
||||
void create_new_segment();
|
||||
|
||||
static void annotation_callback(srd_proto_data *pdata, void *decode_signal);
|
||||
|
||||
Q_SIGNALS:
|
||||
|
@ -171,26 +180,20 @@ private:
|
|||
|
||||
shared_ptr<Logic> logic_mux_data_;
|
||||
shared_ptr<LogicSegment> logic_mux_segment_;
|
||||
uint32_t logic_unit_size_;
|
||||
bool logic_mux_data_invalid_;
|
||||
|
||||
pv::util::Timestamp start_time_;
|
||||
double samplerate_;
|
||||
|
||||
int64_t samples_decoded_;
|
||||
uint32_t currently_processed_segment_;
|
||||
|
||||
vector< shared_ptr<decode::Decoder> > stack_;
|
||||
map<pair<const srd_decoder*, int>, decode::Row> class_rows_;
|
||||
|
||||
/// Annotations for all segments
|
||||
vector< map<const decode::Row, decode::RowData>> segmented_rows_;
|
||||
|
||||
/// Set of annotations for current segment
|
||||
map<const decode::Row, decode::RowData> *current_rows_;
|
||||
vector<DecodeSegment> segments_;
|
||||
uint32_t current_segment_id_;
|
||||
DecodeSegment *current_segment_;
|
||||
|
||||
mutable mutex input_mutex_, output_mutex_, logic_mux_mutex_;
|
||||
mutable condition_variable decode_input_cond_, logic_mux_cond_;
|
||||
bool frame_complete_;
|
||||
|
||||
std::thread decode_thread_, logic_mux_thread_;
|
||||
atomic<bool> decode_interrupt_, logic_mux_interrupt_;
|
||||
|
|
|
@ -236,7 +236,7 @@ void DecodeTrace::paint_mid(QPainter &p, ViewItemPaintParams &pp)
|
|||
|
||||
vector<Annotation> annotations;
|
||||
decode_signal_->get_annotation_subset(annotations, row,
|
||||
sample_range.first, sample_range.second);
|
||||
current_segment_, sample_range.first, sample_range.second);
|
||||
if (!annotations.empty()) {
|
||||
draw_annotations(annotations, p, annotation_height, pp, y,
|
||||
base_colour, row_title_width);
|
||||
|
@ -706,7 +706,7 @@ const QString DecodeTrace::get_annotation_at_point(const QPoint &point)
|
|||
vector<pv::data::decode::Annotation> annotations;
|
||||
|
||||
decode_signal_->get_annotation_subset(annotations, visible_rows_[row],
|
||||
sample_range.first, sample_range.second);
|
||||
current_segment_, sample_range.first, sample_range.second);
|
||||
|
||||
return (annotations.empty()) ?
|
||||
QString() : annotations[0].annotations().front();
|
||||
|
|
Loading…
Reference in New Issue