From: Soeren Apel Date: Thu, 19 Dec 2019 08:32:45 +0000 (+0100) Subject: Add save feature to DecoderOutputView X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=13b726cda35835a120ade2d9cc1ab58770d4ef3f;p=pulseview.git Add save feature to DecoderOutputView --- diff --git a/pv/data/decodesignal.cpp b/pv/data/decodesignal.cpp index 00812917..12379518 100644 --- a/pv/data/decodesignal.cpp +++ b/pv/data/decodesignal.cpp @@ -567,7 +567,7 @@ void DecodeSignal::get_binary_data_chunk(uint32_t segment_id, } } -void DecodeSignal::get_binary_data_chunks_merged(uint32_t segment_id, +void DecodeSignal::get_merged_binary_data_chunks_by_sample(uint32_t segment_id, const Decoder* dec, uint32_t bin_class_id, uint64_t start_sample, uint64_t end_sample, vector *dest) const { @@ -608,6 +608,48 @@ void DecodeSignal::get_binary_data_chunks_merged(uint32_t segment_id, } } +void DecodeSignal::get_merged_binary_data_chunks_by_offset(uint32_t segment_id, + const data::decode::Decoder* dec, uint32_t bin_class_id, uint64_t start, + uint64_t end, vector *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 offset = 0; + for (const DecodeBinaryDataChunk& chunk : bin_class->chunks) { + if (offset >= start) + size += chunk.data.size(); + offset += chunk.data.size(); + if (offset >= end) + break; + } + dest->resize(size); + + offset = 0; + uint64_t dest_offset = 0; + for (const DecodeBinaryDataChunk& chunk : bin_class->chunks) { + if (offset >= start) { + memcpy(dest->data() + dest_offset, chunk.data.data(), chunk.data.size()); + dest_offset += chunk.data.size(); + } + offset += chunk.data.size(); + if (offset >= end) + break; + } + } catch (out_of_range&) { + // Do nothing + } +} + const DecodeBinaryClass* DecodeSignal::get_binary_data_class(uint32_t segment_id, const data::decode::Decoder* dec, uint32_t bin_class_id) const { diff --git a/pv/data/decodesignal.hpp b/pv/data/decodesignal.hpp index e591eb01..8bcc5620 100644 --- a/pv/data/decodesignal.hpp +++ b/pv/data/decodesignal.hpp @@ -165,8 +165,13 @@ public: void get_binary_data_chunk(uint32_t segment_id, const data::decode::Decoder* dec, uint32_t bin_class_id, uint32_t chunk_id, const vector **dest, uint64_t *size); - void get_binary_data_chunks_merged(uint32_t segment_id, const data::decode::Decoder* dec, - uint32_t bin_class_id, uint64_t start_sample, uint64_t end_sample, + void get_merged_binary_data_chunks_by_sample(uint32_t segment_id, + const data::decode::Decoder* dec, uint32_t bin_class_id, + uint64_t start_sample, uint64_t end_sample, + vector *dest) const; + void get_merged_binary_data_chunks_by_offset(uint32_t segment_id, + const data::decode::Decoder* dec, uint32_t bin_class_id, + uint64_t start, uint64_t end, vector *dest) const; const DecodeBinaryClass* get_binary_data_class(uint32_t segment_id, const data::decode::Decoder* dec, uint32_t bin_class_id) const; diff --git a/pv/views/decoder_output/QHexView.cpp b/pv/views/decoder_output/QHexView.cpp index 06df103b..0fca4161 100644 --- a/pv/views/decoder_output/QHexView.cpp +++ b/pv/views/decoder_output/QHexView.cpp @@ -126,6 +126,21 @@ QSizePolicy QHexView::sizePolicy() const return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); } +pair QHexView::get_selection() const +{ + size_t start = selectBegin_ / 2; + size_t end = selectEnd_ / 2; + + if (start == end) { + // Nothing is currently selected + start = 0; + end = data_size_; + } else + end++; + + return std::make_pair(start, end); +} + void QHexView::initialize_byte_iterator(size_t offset) { current_chunk_id_ = 0; diff --git a/pv/views/decoder_output/QHexView.hpp b/pv/views/decoder_output/QHexView.hpp index e7c25567..c3004c5c 100644 --- a/pv/views/decoder_output/QHexView.hpp +++ b/pv/views/decoder_output/QHexView.hpp @@ -34,6 +34,7 @@ #include +using std::pair; using std::size_t; using pv::data::DecodeBinaryClass; using pv::data::DecodeBinaryDataChunk; @@ -58,6 +59,8 @@ public: void showFromOffset(size_t offset); virtual QSizePolicy sizePolicy() const; + pair get_selection() const; + protected: void initialize_byte_iterator(size_t offset); uint8_t get_next_byte(bool* is_next_chunk = nullptr); diff --git a/pv/views/decoder_output/view.cpp b/pv/views/decoder_output/view.cpp index 218c5c9a..951bc06e 100644 --- a/pv/views/decoder_output/view.cpp +++ b/pv/views/decoder_output/view.cpp @@ -21,8 +21,10 @@ #include #include +#include #include #include +#include #include #include @@ -31,6 +33,7 @@ #include "view.hpp" #include "QHexView.hpp" +#include "pv/globalsettings.hpp" #include "pv/session.hpp" #include "pv/util.hpp" #include "pv/data/decode/decoder.hpp" @@ -240,6 +243,52 @@ void View::update_data() signal_->get_binary_data_class(current_segment_, decoder_, bin_class_id_); hex_view_->setData(bin_class); + + if (!save_button_->isEnabled()) + save_button_->setEnabled(true); +} + +void View::save_data() const +{ + assert(decoder_); + assert(signal_); + + if (!signal_) + return; + + GlobalSettings settings; + const QString dir = settings.value("MainWindow/SaveDirectory").toString(); + + const QString file_name = QFileDialog::getSaveFileName( + parent_, tr("Save Binary Data"), dir, tr("Binary Data Files (*.bin);;All Files (*)")); + + if (file_name.isEmpty()) + return; + + QFile file(file_name); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + pair selection = hex_view_->get_selection(); + + vector data; + signal_->get_merged_binary_data_chunks_by_offset(current_segment_, decoder_, + bin_class_id_, selection.first, selection.second, &data); + + int64_t bytes_written = file.write((const char*)data.data(), data.size()); + + if ((bytes_written == -1) || ((uint64_t)bytes_written != data.size())) { + QMessageBox msg(parent_); + msg.setText(tr("Error") + "\n\n" + tr("File %1 could not be written to.").arg(file_name)); + msg.setStandardButtons(QMessageBox::Ok); + msg.setIcon(QMessageBox::Warning); + msg.exec(); + return; + } + } +} + +void View::save_data_as_hex_dump() const +{ + } void View::on_selected_decoder_changed(int index) @@ -359,18 +408,22 @@ void View::on_decoder_removed(void* decoder) void View::on_actionSave_triggered(QAction* action) { - (void)action; + int save_type = SaveTypeBinary; + if (action) + save_type = action->data().toInt(); + + if (save_type == SaveTypeBinary) + save_data(); + if (save_type == SaveTypeHexDump) + save_data_as_hex_dump(); } void View::perform_delayed_view_update() { if (!binary_data_exists_) - if (signal_->get_binary_data_chunk_count(current_segment_, decoder_, bin_class_id_)) { + if (signal_->get_binary_data_chunk_count(current_segment_, decoder_, bin_class_id_)) binary_data_exists_ = true; - save_button_->setEnabled(true); - } - update_data(); } diff --git a/pv/views/decoder_output/view.hpp b/pv/views/decoder_output/view.hpp index ece85ad6..28c7e906 100644 --- a/pv/views/decoder_output/view.hpp +++ b/pv/views/decoder_output/view.hpp @@ -76,6 +76,9 @@ private: void reset_data(); void update_data(); + void save_data() const; + void save_data_as_hex_dump() const; + private Q_SLOTS: void on_selected_decoder_changed(int index); void on_selected_class_changed(int index);