}
}
-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<uint8_t> *dest) const
{
}
}
+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<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 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
{
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<uint8_t> **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<uint8_t> *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<uint8_t> *dest) const;
const DecodeBinaryClass* get_binary_data_class(uint32_t segment_id,
const data::decode::Decoder* dec, uint32_t bin_class_id) const;
return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
}
+pair<size_t, size_t> 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;
#include <pv/data/decodesignal.hpp>
+using std::pair;
using std::size_t;
using pv::data::DecodeBinaryClass;
using pv::data::DecodeBinaryDataChunk;
void showFromOffset(size_t offset);
virtual QSizePolicy sizePolicy() const;
+ pair<size_t, size_t> get_selection() const;
+
protected:
void initialize_byte_iterator(size_t offset);
uint8_t get_next_byte(bool* is_next_chunk = nullptr);
#include <QByteArray>
#include <QDebug>
+#include <QFileDialog>
#include <QLabel>
#include <QMenu>
+#include <QMessageBox>
#include <QToolBar>
#include <QVBoxLayout>
#include "view.hpp"
#include "QHexView.hpp"
+#include "pv/globalsettings.hpp"
#include "pv/session.hpp"
#include "pv/util.hpp"
#include "pv/data/decode/decoder.hpp"
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<size_t, size_t> selection = hex_view_->get_selection();
+
+ vector<uint8_t> 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)
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();
}
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);