shown_(true),
decoder_inst_(nullptr)
{
+ // Query the decoder outputs
+ uint8_t i = 0;
+ for (GSList *l = dec->binary; l; l = l->next) {
+ char **bin_class = (char**)l->data;
+ char *name = bin_class[0];
+ char *desc = bin_class[1];
+ bin_classes_.push_back({i++, name, desc});
+ }
}
Decoder::~Decoder()
return decoder_;
}
+const char* Decoder::name() const
+{
+ return decoder_->name;
+}
+
bool Decoder::shown() const
{
return shown_;
decoder_inst_ = nullptr;
}
+uint8_t Decoder::get_binary_class_count() const
+{
+ return bin_classes_.size();
+}
+
+const DecodeBinaryClassInfo* Decoder::get_binary_class(uint8_t id) const
+{
+ return &(bin_classes_.at(id));
+}
+
} // namespace decode
} // namespace data
} // namespace pv
const srd_channel *pdch_;
};
+struct DecodeBinaryClassInfo
+{
+ uint8_t bin_class_id;
+ char* name;
+ char* description;
+};
+
class Decoder
{
const srd_decoder* decoder() const;
+ const char* name() const;
+
bool shown() const;
void show(bool show = true);
srd_decoder_inst* create_decoder_inst(srd_session *session);
void invalidate_decoder_inst();
-
+ uint8_t get_binary_class_count() const;
+ const DecodeBinaryClassInfo* get_binary_class(uint8_t id) const;
private:
const srd_decoder *const decoder_;
bool shown_;
vector<DecodeChannel*> channels_;
+ vector<DecodeBinaryClassInfo> bin_classes_;
map<string, GVariant*> options_;
srd_decoder_inst *decoder_inst_;
};
stack_config_changed_ = true;
auto_assign_signals(dec);
commit_decoder_channels();
+
+ decoder_stacked((void*)dec.get());
+
begin_decode();
}
for (int i = 0; i < index; i++, iter++)
assert(iter != stack_.end());
+ decoder_removed(iter->get());
+
// Delete the element
stack_.erase(iter);
delete all_ann_list;
}
-uint32_t DecodeSignal::get_binary_data_chunk_count(uint32_t segment_id) const
+uint32_t DecodeSignal::get_binary_data_chunk_count(uint32_t segment_id,
+ const Decoder* dec, uint8_t bin_class_id) const
{
- uint32_t count = 0;
-
try {
const DecodeSegment *segment = &(segments_.at(segment_id));
- count = segment->binary_data.size();
+
+ for (const DecodeBinaryClass& bc : segment->binary_classes)
+ if ((bc.decoder == dec) && (bc.info->bin_class_id == bin_class_id))
+ return bc.chunks.size();
} catch (out_of_range&) {
// Do nothing
}
- return count;
+ return 0;
}
-void DecodeSignal::get_binary_data_chunk(uint32_t segment_id, uint32_t chunk_id,
+void DecodeSignal::get_binary_data_chunk(uint32_t segment_id,
+ const Decoder* dec, uint8_t bin_class_id, uint32_t chunk_id,
const vector<uint8_t> **dest, uint64_t *size)
{
try {
const DecodeSegment *segment = &(segments_.at(segment_id));
- if (dest)
- *dest = &(segment->binary_data.at(chunk_id).data);
- if (size)
- *size = segment->binary_data.at(chunk_id).data.size();
+
+ for (const DecodeBinaryClass& bc : segment->binary_classes)
+ if ((bc.decoder == dec) && (bc.info->bin_class_id == bin_class_id)) {
+ if (dest) *dest = &(bc.chunks.at(chunk_id).data);
+ if (size) *size = bc.chunks.at(chunk_id).data.size();
+ return;
+ }
} catch (out_of_range&) {
// Do nothing
}
}
void DecodeSignal::get_binary_data_chunks_merged(uint32_t segment_id,
- uint64_t start_sample, uint64_t end_sample, vector<uint8_t> *dest) const
+ const Decoder* dec, uint8_t bin_class_id, uint64_t start_sample,
+ uint64_t end_sample, vector<uint8_t> *dest) const
{
assert(dest != nullptr);
try {
const DecodeSegment *segment = &(segments_.at(segment_id));
+ const DecodeBinaryClass* bin_class = nullptr;
+ for (const DecodeBinaryClass& bc : segment->binary_classes)
+ if ((bc.decoder == dec) && (bc.info->bin_class_id == bin_class_id))
+ bin_class = &bc;
+
// Determine overall size before copying to resize dest vector only once
uint64_t size = 0;
uint64_t matches = 0;
- for (const DecodeBinaryData& d : segment->binary_data)
- if ((d.sample >= start_sample) && (d.sample < end_sample)) {
- size += d.data.size();
+ for (const DecodeBinaryDataChunk& chunk : bin_class->chunks)
+ if ((chunk.sample >= start_sample) && (chunk.sample < end_sample)) {
+ size += chunk.data.size();
matches++;
}
dest->resize(size);
uint64_t offset = 0;
uint64_t matches2 = 0;
- for (const DecodeBinaryData& d : segment->binary_data)
- if ((d.sample >= start_sample) && (d.sample < end_sample)) {
- memcpy(dest->data() + offset, d.data.data(), d.data.size());
- offset += d.data.size();
+ for (const DecodeBinaryDataChunk& chunk : bin_class->chunks)
+ if ((chunk.sample >= start_sample) && (chunk.sample < end_sample)) {
+ memcpy(dest->data() + offset, chunk.data.data(), chunk.data.size());
+ offset += chunk.data.size();
matches2++;
// Make sure we don't overwrite memory if the array grew in the meanwhile
decode::RowData();
}
}
+
+ // Prepare our binary output classes
+ for (const shared_ptr<decode::Decoder>& dec : stack_) {
+ uint8_t n = dec->get_binary_class_count();
+
+ for (uint8_t i = 0; i < n; i++)
+ segments_.back().binary_classes.push_back(
+ {dec.get(), dec->get_binary_class(i), vector<DecodeBinaryDataChunk>()});
+ }
}
void DecodeSignal::annotation_callback(srd_proto_data *pdata, void *decode_signal)
if (ds->decode_interrupt_)
return;
+ // Get the decoder and the binary data
+ assert(pdata->pdo);
+ assert(pdata->pdo->di);
+ const srd_decoder *const decc = pdata->pdo->di->decoder;
+ assert(decc);
+
const srd_proto_data_binary *const pdb = (const srd_proto_data_binary*)pdata->data;
assert(pdb);
+ // Find the matching DecodeBinaryClass
DecodeSegment* segment = &(ds->segments_.at(ds->current_segment_id_));
- segment->binary_data.emplace_back();
- DecodeBinaryData* bin_data = &(segment->binary_data.back());
+ DecodeBinaryClass* bin_class = nullptr;
+ for (DecodeBinaryClass& bc : segment->binary_classes)
+ if ((bc.decoder->decoder() == decc) && (bc.info->bin_class_id == pdb->bin_class))
+ bin_class = &bc;
- bin_data->sample = pdata->start_sample;
- bin_data->data.resize(pdb->size);
- memcpy(bin_data->data.data(), pdb->data, pdb->size);
+ if (!bin_class) {
+ qWarning() << "Could not find valid DecodeBinaryClass in segment" <<
+ ds->current_segment_id_ << "for binary class ID" << pdb->bin_class <<
+ ", segment only knows" << segment->binary_classes.size() << "classes";
+ return;
+ }
- ds->new_binary_data(ds->current_segment_id_);
+ // Add the data chunk
+ bin_class->chunks.emplace_back();
+ DecodeBinaryDataChunk* chunk = &(bin_class->chunks.back());
+
+ chunk->sample = pdata->start_sample;
+ chunk->data.resize(pdb->size);
+ memcpy(chunk->data.data(), pdb->data, pdb->size);
+
+ // Note: using pdb->bin_class is only unique for each decoder in the stack,
+ // so if two stacked decoders both emit binary data with the same bin_class,
+ // we may be triggering unnecessary updates. Should be ok for now as that
+ // case isn't possible yet. When it is, we might add the decoder's name
+ // as an additional parameter to the signal, although string comparisons
+ // are not really fast.
+ ds->new_binary_data(ds->current_segment_id_, pdb->bin_class);
}
void DecodeSignal::on_capture_state_changed(int state)
class SignalBase;
class SignalData;
-struct DecodeBinaryData
+struct DecodeBinaryDataChunk
{
vector<uint8_t> data;
uint64_t sample; ///< Number of the sample where this data was provided by the PD
};
+struct DecodeBinaryClass
+{
+ const decode::Decoder* decoder;
+ const decode::DecodeBinaryClassInfo* info;
+ vector<DecodeBinaryDataChunk> chunks;
+};
+
struct DecodeSegment
{
map<const decode::Row, decode::RowData> annotation_rows;
pv::util::Timestamp start_time;
double samplerate;
int64_t samples_decoded_incl, samples_decoded_excl;
- vector<DecodeBinaryData> binary_data;
+ vector<DecodeBinaryClass> binary_classes;
};
class DecodeSignal : public SignalBase
vector<pv::data::decode::Annotation> &dest,
uint32_t segment_id, uint64_t start_sample, uint64_t end_sample) const;
- uint32_t get_binary_data_chunk_count(uint32_t segment_id) const;
- void get_binary_data_chunk(uint32_t segment_id, uint32_t chunk_id,
- const vector<uint8_t> **dest, uint64_t *size);
- void get_binary_data_chunks_merged(uint32_t segment_id,
- uint64_t start_sample, uint64_t end_sample, vector<uint8_t> *dest) const;
+ uint32_t get_binary_data_chunk_count(uint32_t segment_id,
+ const data::decode::Decoder* dec, uint8_t bin_class_id) const;
+ void get_binary_data_chunk(uint32_t segment_id, const data::decode::Decoder* dec,
+ uint8_t bin_class_id, uint32_t chunk_id, const vector<uint8_t> **dest,
+ uint64_t *size);
+ void get_binary_data_chunks_merged(uint32_t segment_id, const data::decode::Decoder* dec,
+ uint8_t bin_class_id, uint64_t start_sample, uint64_t end_sample,
+ vector<uint8_t> *dest) const;
virtual void save_settings(QSettings &settings) const;
static void binary_callback(srd_proto_data *pdata, void *decode_signal);
Q_SIGNALS:
+ void decoder_stacked(void* decoder); ///< decoder is of type decode::Decoder*
+ void decoder_removed(void* decoder); ///< decoder is of type decode::Decoder*
void new_annotations(); // TODO Supply segment for which they belong to
- void new_binary_data(unsigned int segment_id);
+ void new_binary_data(unsigned int segment_id, unsigned int bin_class_id);
void decode_reset();
void decode_finished();
void channels_updated();
#include "pv/session.hpp"
#include "pv/util.hpp"
+#include "pv/data/decode/decoder.hpp"
using pv::data::DecodeSignal;
using pv::data::SignalBase;
+using pv::data::decode::Decoder;
using pv::util::TimeUnit;
using pv::util::Timestamp;
+using std::dynamic_pointer_cast;
using std::numeric_limits;
using std::shared_ptr;
ViewBase(session, is_main_view, parent),
// Note: Place defaults in View::reset_view_state(), not here
- signal_selector_(new QComboBox()),
+ decoder_selector_(new QComboBox()),
format_selector_(new QComboBox()),
+ class_selector_(new QComboBox()),
stacked_widget_(new QStackedWidget()),
hex_view_(new QHexView()),
signal_(nullptr),
// Populate toolbar
toolbar->addWidget(new QLabel(tr("Decoder:")));
- toolbar->addWidget(signal_selector_);
+ toolbar->addWidget(decoder_selector_);
+ toolbar->addWidget(class_selector_);
toolbar->addSeparator();
toolbar->addWidget(new QLabel(tr("Show data as")));
toolbar->addWidget(format_selector_);
stacked_widget_->addWidget(hex_view_);
stacked_widget_->setCurrentIndex(0);
- connect(signal_selector_, SIGNAL(currentIndexChanged(int)),
- this, SLOT(on_selected_signal_changed(int)));
+ connect(decoder_selector_, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(on_selected_decoder_changed(int)));
hex_view_->setData(merged_data_);
void View::clear_decode_signals()
{
- signal_selector_->clear();
+ ViewBase::clear_decode_signals();
+
+ decoder_selector_->clear();
format_selector_->setCurrentIndex(0);
signal_ = nullptr;
}
void View::add_decode_signal(shared_ptr<data::DecodeSignal> signal)
{
+ ViewBase::add_decode_signal(signal);
+
connect(signal.get(), SIGNAL(name_changed(const QString&)),
this, SLOT(on_signal_name_changed(const QString&)));
-
- signal_selector_->addItem(signal->name(), QVariant::fromValue((void*)signal.get()));
+ connect(signal.get(), SIGNAL(decoder_stacked(void*)),
+ this, SLOT(on_decoder_stacked(void*)));
+ connect(signal.get(), SIGNAL(decoder_removed(void*)),
+ this, SLOT(on_decoder_removed(void*)));
+
+ // Add all decoders provided by this signal
+ auto stack = signal->decoder_stack();
+ if (stack.size() > 1) {
+ for (const shared_ptr<Decoder>& dec : stack) {
+ QString title = QString("%1 (%2)").arg(signal->name(), dec->name());
+ decoder_selector_->addItem(title, QVariant::fromValue((void*)dec.get()));
+ }
+ } else
+ if (!stack.empty()) {
+ shared_ptr<Decoder>& dec = stack.at(0);
+ decoder_selector_->addItem(signal->name(), QVariant::fromValue((void*)dec.get()));
+ }
}
void View::remove_decode_signal(shared_ptr<data::DecodeSignal> signal)
{
- int index = signal_selector_->findData(QVariant::fromValue((void*)signal.get()));
+ // Remove all decoders provided by this signal
+ for (const shared_ptr<Decoder>& dec : signal->decoder_stack()) {
+ int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
- if (index != -1)
- signal_selector_->removeItem(index);
+ if (index != -1)
+ decoder_selector_->removeItem(index);
+ }
+
+ ViewBase::remove_decode_signal(signal);
if (signal.get() == signal_) {
signal_ = nullptr;
+ decoder_ = nullptr;
+ bin_class_id_ = 0;
update_data();
}
}
return;
}
- if (signal_->get_binary_data_chunk_count(current_segment_) == 0) {
+ if (signal_->get_binary_data_chunk_count(current_segment_, decoder_, bin_class_id_) == 0) {
merged_data_->clear();
return;
}
vector<uint8_t> data;
- signal_->get_binary_data_chunks_merged(current_segment_, 0,
- numeric_limits<uint64_t>::max(), &data);
+ signal_->get_binary_data_chunks_merged(current_segment_, decoder_, bin_class_id_,
+ 0, numeric_limits<uint64_t>::max(), &data);
merged_data_->resize(data.size());
memcpy(merged_data_->data(), data.data(), data.size());
}
-void View::on_selected_signal_changed(int index)
+void View::on_selected_decoder_changed(int index)
{
if (signal_)
- disconnect(signal_, SIGNAL(new_binary_data(unsigned int)));
+ disconnect(signal_, SIGNAL(new_binary_data(unsigned int, unsigned int)));
- signal_ = (DecodeSignal*)signal_selector_->itemData(index).value<void*>();
- update_data();
+ decoder_ = (Decoder*)decoder_selector_->itemData(index).value<void*>();
+
+ // Find the signal that contains the selected decoder
+ signal_ = nullptr;
+
+ for (const shared_ptr<data::SignalBase>& sb : signalbases_) {
+ shared_ptr<DecodeSignal> ds = dynamic_pointer_cast<DecodeSignal>(sb);
+
+ if (ds)
+ for (const shared_ptr<Decoder>& dec : ds->decoder_stack())
+ if (decoder_ == dec.get())
+ signal_ = ds.get();
+ }
if (signal_)
- connect(signal_, SIGNAL(new_binary_data(unsigned int)),
- this, SLOT(on_new_binary_data(unsigned int)));
+ connect(signal_, SIGNAL(new_binary_data(unsigned int, unsigned int)),
+ this, SLOT(on_new_binary_data(unsigned int, unsigned int)));
+
+ update_data();
}
void View::on_signal_name_changed(const QString &name)
{
- SignalBase *sb = qobject_cast<SignalBase*>(QObject::sender());
+ (void)name;
+
+ SignalBase* sb = qobject_cast<SignalBase*>(QObject::sender());
assert(sb);
- int index = signal_selector_->findData(QVariant::fromValue(sb));
- if (index != -1)
- signal_selector_->setItemText(index, name);
+ DecodeSignal* signal = dynamic_cast<DecodeSignal*>(sb);
+ assert(signal);
+
+ // Update all decoder entries provided by this signal
+ auto stack = signal->decoder_stack();
+ if (stack.size() > 1) {
+ for (const shared_ptr<Decoder>& dec : stack) {
+ QString title = QString("%1 (%2)").arg(signal->name(), dec->name());
+ int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
+
+ if (index != -1)
+ decoder_selector_->setItemText(index, title);
+ }
+ } else
+ if (!stack.empty()) {
+ shared_ptr<Decoder>& dec = stack.at(0);
+ int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
+
+ if (index != -1)
+ decoder_selector_->setItemText(index, signal->name());
+ }
}
-void View::on_new_binary_data(unsigned int segment_id)
+void View::on_new_binary_data(unsigned int segment_id, unsigned int bin_class_id)
{
- if (segment_id == current_segment_)
+ if ((segment_id == current_segment_) && (bin_class_id == bin_class_id_))
update_data();
}
+void View::on_decoder_stacked(void* decoder)
+{
+ // TODO This doesn't change existing entries for the same signal - but it should as the naming scheme may change
+
+ Decoder* d = static_cast<Decoder*>(decoder);
+
+ // Find the signal that contains the selected decoder
+ DecodeSignal* signal = nullptr;
+
+ for (const shared_ptr<DecodeSignal>& ds : decode_signals_)
+ for (const shared_ptr<Decoder>& dec : ds->decoder_stack())
+ if (d == dec.get())
+ signal = ds.get();
+
+ assert(signal);
+
+ // Add the decoder to the list
+ QString title = QString("%1 (%2)").arg(signal->name(), d->name());
+ decoder_selector_->addItem(title, QVariant::fromValue((void*)d));
+}
+
+void View::on_decoder_removed(void* decoder)
+{
+ Decoder* d = static_cast<Decoder*>(decoder);
+
+ // Remove the decoder from the list
+ int index = decoder_selector_->findData(QVariant::fromValue((void*)d));
+
+ if (index != -1)
+ decoder_selector_->removeItem(index);
+}
+
+
} // namespace decoder_output
} // namespace views
} // namespace pv
void update_data();
private Q_SLOTS:
- void on_selected_signal_changed(int index);
+ void on_selected_decoder_changed(int index);
void on_signal_name_changed(const QString &name);
- void on_new_binary_data(unsigned int segment_id);
+ void on_new_binary_data(unsigned int segment_id, unsigned int bin_class_id);
+
+ void on_decoder_stacked(void* decoder);
+ void on_decoder_removed(void* decoder);
private:
- QComboBox *signal_selector_, *format_selector_;
+ QComboBox *decoder_selector_, *format_selector_, *class_selector_;
QStackedWidget *stacked_widget_;
QHexView *hex_view_;
data::DecodeSignal *signal_;
+ const data::decode::Decoder *decoder_;
+ uint8_t bin_class_id_;
QByteArray *merged_data_;
};
#ifdef ENABLE_DECODE
void View::clear_decode_signals()
{
+ ViewBase::clear_decode_signals();
decode_traces_.clear();
}
void View::add_decode_signal(shared_ptr<data::DecodeSignal> signal)
{
+ ViewBase::add_decode_signal(signal);
+
shared_ptr<DecodeTrace> d(
new DecodeTrace(session_, signal, decode_traces_.size()));
decode_traces_.push_back(d);
signals_changed();
return;
}
+
+ ViewBase::remove_decode_signal(signal);
}
#endif
#ifdef ENABLE_DECODE
void ViewBase::clear_decode_signals()
{
+ decode_signals_.clear();
}
void ViewBase::add_decode_signal(shared_ptr<data::DecodeSignal> signal)
{
- (void)signal;
+ decode_signals_.insert(signal);
}
void ViewBase::remove_decode_signal(shared_ptr<data::DecodeSignal> signal)
{
- (void)signal;
+ decode_signals_.erase(signal);
}
#endif
util::TimeUnit time_unit_;
unordered_set< shared_ptr<data::SignalBase> > signalbases_;
+#ifdef ENABLE_DECODE
+ unordered_set< shared_ptr<data::DecodeSignal> > decode_signals_;
+#endif
/// The ID of the currently displayed segment
uint32_t current_segment_;