session_(session),
srd_session_(nullptr),
logic_mux_data_invalid_(false),
+ stack_config_changed_(true),
current_segment_id_(0)
{
connect(&session_, SIGNAL(capture_state_changed(int)),
// Include the newly created decode channels in the channel lists
update_channel_list();
+ stack_config_changed_ = true;
auto_assign_signals(dec);
commit_decoder_channels();
begin_decode();
stack_.erase(iter);
// Update channels and decoded data
+ stack_config_changed_ = true;
update_channel_list();
begin_decode();
}
void DecodeSignal::reset_decode()
{
+ if (stack_config_changed_)
+ stop_srd_session();
+ else
+ terminate_srd_session();
+
if (decode_thread_.joinable()) {
decode_interrupt_ = true;
decode_input_cond_.notify_one();
logic_mux_thread_.join();
}
- stop_srd_session();
-
class_rows_.clear();
current_segment_id_ = 0;
segments_.clear();
return;
}
- create_segments();
-
// 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);
if (new_assignment) {
logic_mux_data_invalid_ = true;
+ stack_config_changed_ = true;
commit_decoder_channels();
channels_updated();
}
logic_mux_data_invalid_ = true;
}
+ stack_config_changed_ = true;
commit_decoder_channels();
channels_updated();
begin_decode();
if (ch.id == channel_id)
ch.initial_pin_state = init_state;
+ stack_config_changed_ = true;
channels_updated();
-
begin_decode();
}
try {
const shared_ptr<LogicSegment> segment = logic_data->logic_segments().at(segment_id);
count = min(count, (int64_t)segment->get_sample_count());
- } catch (out_of_range) {
+ } catch (out_of_range&) {
return 0;
}
}
try {
const DecodeSegment *segment = &(segments_.at(segment_id));
result = segment->samples_decoded;
- } catch (out_of_range) {
+ } catch (out_of_range&) {
// Do nothing
}
if (iter != rows->end())
(*iter).second.get_annotation_subset(dest,
start_sample, end_sample);
- } catch (out_of_range) {
+ } catch (out_of_range&) {
// Do nothing
}
}
}
// Update the internal structures
+ stack_config_changed_ = true;
update_channel_list();
commit_decoder_channels();
try {
const shared_ptr<LogicSegment> segment = logic_data->logic_segments().at(segment_id);
samplerate = segment->samplerate();
- } catch (out_of_range) {
+ } catch (out_of_range&) {
// Do nothing
}
break;
shared_ptr<LogicSegment> segment;
try {
segment = logic_data->logic_segments().at(segment_id);
- } catch (out_of_range) {
+ } catch (out_of_range&) {
qDebug() << "Muxer error for" << name() << ":" << ch.assigned_signal->name() \
<< "has no logic segment" << segment_id;
return;
shared_ptr<LogicSegment> output_segment;
try {
output_segment = logic_mux_data_->logic_segments().at(segment_id);
- } catch (out_of_range) {
+ } catch (out_of_range&) {
qDebug() << "Muxer error for" << name() << ": no logic mux segment" \
<< segment_id << "in mux_logic_samples(), mux segments size is" \
<< logic_mux_data_->logic_segments().size();
assert(logic_mux_data_);
- shared_ptr<LogicSegment> output_segment = logic_mux_data_->logic_segments().front();
- assert(output_segment);
+ // Create initial logic mux segment
+ shared_ptr<LogicSegment> output_segment =
+ make_shared<LogicSegment>(*logic_mux_data_, segment_id,
+ logic_mux_unit_size_, 0);
+ logic_mux_data_->push_segment(output_segment);
output_segment->set_samplerate(get_input_samplerate(0));
// Process next segment
segment_id++;
- try {
- output_segment = logic_mux_data_->logic_segments().at(segment_id);
- } catch (out_of_range) {
- qDebug() << "Muxer error for" << name() << ": no logic mux segment" \
- << segment_id << "in logic_mux_proc(), mux segments size is" \
- << logic_mux_data_->logic_segments().size();
- return;
- }
+ output_segment =
+ make_shared<LogicSegment>(*logic_mux_data_, segment_id,
+ logic_mux_unit_size_, 0);
+ logic_mux_data_->push_segment(output_segment);
output_segment->set_samplerate(get_input_samplerate(segment_id));
} while (!logic_mux_interrupt_);
}
-void DecodeSignal::query_input_metadata()
-{
- // Update the samplerate and start time because we cannot start
- // the libsrd session without the current samplerate
-
- // TODO Currently we assume all channels have the same sample rate
- // and start time
- bool samplerate_valid = false;
- data::DecodeChannel *any_channel;
- shared_ptr<Logic> logic_data;
-
- do {
- any_channel = &(*find_if(channels_.begin(), channels_.end(),
- [](data::DecodeChannel ch) { return ch.assigned_signal; }));
-
- logic_data = any_channel->assigned_signal->logic_data();
-
- if (!logic_data) {
- // Wait until input data is available or an interrupt was requested
- unique_lock<mutex> input_wait_lock(input_mutex_);
- decode_input_cond_.wait(input_wait_lock);
- }
- } while (!logic_data && !decode_interrupt_);
-
- if (decode_interrupt_)
- return;
-
- do {
- if (!logic_data->logic_segments().empty()) {
- shared_ptr<LogicSegment> first_segment =
- any_channel->assigned_signal->logic_data()->logic_segments().front();
-
- // We only need valid metadata in the first decode segment
- // so that start_srd_session() can use it
- segments_.at(current_segment_id_).start_time = first_segment->start_time();
- segments_.at(current_segment_id_).samplerate = first_segment->samplerate();
-
- if (segments_.at(current_segment_id_).samplerate > 0)
- samplerate_valid = true;
- }
-
- if (!samplerate_valid) {
- // Wait until input data is available or an interrupt was requested
- unique_lock<mutex> input_wait_lock(input_mutex_);
- decode_input_cond_.wait(input_wait_lock);
- }
- } while (!samplerate_valid && !decode_interrupt_);
-}
-
void DecodeSignal::decode_data(
const int64_t abs_start_samplenum, const int64_t sample_count,
const shared_ptr<LogicSegment> input_segment)
void DecodeSignal::decode_proc()
{
- query_input_metadata();
+ current_segment_id_ = 0;
+
+ // If there is no input data available yet, wait until it is or we're interrupted
+ if (logic_mux_data_->logic_segments().size() == 0) {
+ unique_lock<mutex> input_wait_lock(input_mutex_);
+ decode_input_cond_.wait(input_wait_lock);
+ }
if (decode_interrupt_)
return;
- start_srd_session();
-
- current_segment_id_ = 0;
shared_ptr<LogicSegment> input_segment = logic_mux_data_->logic_segments().front();
-
assert(input_segment);
+
+ // Create the initial segment and set its sample rate so that we can pass it to SRD
+ create_decode_segment();
segments_.at(current_segment_id_).samplerate = input_segment->samplerate();
+ segments_.at(current_segment_id_).start_time = input_segment->start_time();
- uint64_t sample_count;
+ start_srd_session();
+
+ uint64_t sample_count = 0;
uint64_t abs_start_samplenum = 0;
do {
// Keep processing new samples until we exhaust the input data
try {
input_segment = logic_mux_data_->logic_segments().at(current_segment_id_);
- } catch (out_of_range) {
+ } catch (out_of_range&) {
qDebug() << "Decode error for" << name() << ": no logic mux segment" \
<< current_segment_id_ << "in decode_proc(), mux segments size is" \
<< logic_mux_data_->logic_segments().size();
}
abs_start_samplenum = 0;
+ // Create the next segment and set its metadata
+ create_decode_segment();
segments_.at(current_segment_id_).samplerate = input_segment->samplerate();
+ segments_.at(current_segment_id_).start_time = input_segment->start_time();
// Reset decoder state
stop_srd_session();
}
}
} while (error_message_.isEmpty() && !decode_interrupt_);
+
+ // Potentially reap decoders when the application no longer is
+ // interested in their (pending) results.
+ if (decode_interrupt_)
+ terminate_srd_session();
}
void DecodeSignal::start_srd_session()
{
- if (srd_session_)
- stop_srd_session();
+ uint64_t samplerate;
+
+ if (srd_session_) {
+ // When a decoder stack was created before, re-use it
+ // for the next stream of input data, after terminating
+ // potentially still executing operations, and resetting
+ // internal state. Skip the rather expensive (teardown
+ // and) construction of another decoder stack.
+
+ // TODO Reduce redundancy, use a common code path for
+ // the meta/cb/start sequence?
+ terminate_srd_session();
+ srd_session_metadata_set(srd_session_, SRD_CONF_SAMPLERATE,
+ g_variant_new_uint64(segments_.at(current_segment_id_).samplerate));
+ srd_pd_output_callback_add(srd_session_, SRD_OUTPUT_ANN,
+ DecodeSignal::annotation_callback, this);
+ srd_session_start(srd_session_);
+ return;
+ }
// Create the session
srd_session_new(&srd_session_);
if (!di) {
error_message_ = tr("Failed to create decoder instance");
srd_session_destroy(srd_session_);
+ srd_session_ = nullptr;
return;
}
}
// Start the session
- srd_session_metadata_set(srd_session_, SRD_CONF_SAMPLERATE,
- g_variant_new_uint64(segments_.at(current_segment_id_).samplerate));
+ samplerate = segments_.at(current_segment_id_).samplerate;
+ if (samplerate)
+ srd_session_metadata_set(srd_session_, SRD_CONF_SAMPLERATE,
+ g_variant_new_uint64(samplerate));
srd_pd_output_callback_add(srd_session_, SRD_OUTPUT_ANN,
DecodeSignal::annotation_callback, this);
srd_session_start(srd_session_);
+
+ // We just recreated the srd session, so all stack changes are applied now
+ stack_config_changed_ = false;
+}
+
+void DecodeSignal::terminate_srd_session()
+{
+ // Call the "terminate and reset" routine for the decoder stack
+ // (if available). This does not harm those stacks which already
+ // have completed their operation, and reduces response time for
+ // those stacks which still are processing data while the
+ // application no longer wants them to.
+ if (srd_session_)
+ srd_session_terminate_reset(srd_session_);
}
void DecodeSignal::stop_srd_session()
const data::SignalBase *signal = ch.assigned_signal;
connect(signal, SIGNAL(samples_cleared()),
this, SLOT(on_data_cleared()));
- connect(signal, SIGNAL(samples_added(QObject*, uint64_t, uint64_t)),
+ connect(signal, SIGNAL(samples_added(uint64_t, uint64_t, uint64_t)),
this, SLOT(on_data_received()));
}
}
-void DecodeSignal::create_segments()
+void DecodeSignal::create_decode_segment()
{
- // Make sure we have as many segments as we need
- const uint32_t input_segment_count = get_input_segment_count();
+ // Create annotation segment
+ segments_.emplace_back(DecodeSegment());
- for (uint32_t i = logic_mux_data_->logic_segments().size(); i < input_segment_count; i++) {
- shared_ptr<LogicSegment> segment =
- make_shared<LogicSegment>(*logic_mux_data_, logic_mux_unit_size_, 0);
- logic_mux_data_->push_segment(segment);
- }
-
- for (uint32_t i = segments_.size(); i < input_segment_count; i++) {
- // Create annotation segment
- segments_.emplace_back(DecodeSegment());
-
- // Add annotation classes
- for (const shared_ptr<decode::Decoder> &dec : stack_) {
- assert(dec);
- const srd_decoder *const decc = dec->decoder();
- assert(dec->decoder());
+ // Add annotation classes
+ for (const shared_ptr<decode::Decoder> &dec : stack_) {
+ assert(dec);
+ const srd_decoder *const decc = dec->decoder();
+ assert(dec->decoder());
- // Add a row for the decoder if it doesn't have a row list
- if (!decc->annotation_rows)
- (segments_.back().annotation_rows)[Row(decc)] =
- decode::RowData();
+ // Add a row for the decoder if it doesn't have a row list
+ if (!decc->annotation_rows)
+ (segments_.back().annotation_rows)[Row(decc)] =
+ decode::RowData();
- // Add the decoder rows
- for (const GSList *l = decc->annotation_rows; l; l = l->next) {
- const srd_decoder_annotation_row *const ann_row =
- (srd_decoder_annotation_row *)l->data;
- assert(ann_row);
+ // Add the decoder rows
+ for (const GSList *l = decc->annotation_rows; l; l = l->next) {
+ const srd_decoder_annotation_row *const ann_row =
+ (srd_decoder_annotation_row *)l->data;
+ assert(ann_row);
- const Row row(decc, ann_row);
+ const Row row(decc, ann_row);
- // Add a new empty row data object
- (segments_.back().annotation_rows)[row] =
- decode::RowData();
- }
+ // Add a new empty row data object
+ (segments_.back().annotation_rows)[row] =
+ decode::RowData();
}
}
}
void DecodeSignal::on_data_received()
{
- create_segments();
-
if (!logic_mux_thread_.joinable())
begin_decode();
else