From 1c6f0616734e7caec827b118e52f8fa895be56d9 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 12 Jan 2024 15:39:19 +0800 Subject: [PATCH] able to set range for data saving, and fix a bug of store module --- DSView/pv/data/logicsnapshot.cpp | 9 ++ DSView/pv/data/logicsnapshot.h | 2 + DSView/pv/dialogs/storeprogress.cpp | 152 ++++++++++++++++++++++++---- DSView/pv/dialogs/storeprogress.h | 15 +++ DSView/pv/mainwindow.cpp | 2 + DSView/pv/storesession.cpp | 138 +++++++++++++++++++++++-- DSView/pv/storesession.h | 10 +- DSView/pv/view/view.cpp | 14 +++ DSView/pv/view/view.h | 2 + lang/cn/dlg.json | 10 +- lang/cn/msg.json | 4 + lang/en/dlg.json | 8 ++ lang/en/msg.json | 4 + libsigrok4DSL/libsigrok.h | 2 + libsigrok4DSL/output/csv.c | 4 + libsigrok4DSL/session_driver.c | 1 + 16 files changed, 346 insertions(+), 31 deletions(-) diff --git a/DSView/pv/data/logicsnapshot.cpp b/DSView/pv/data/logicsnapshot.cpp index ff7c1e6e..cd4eb3f8 100644 --- a/DSView/pv/data/logicsnapshot.cpp +++ b/DSView/pv/data/logicsnapshot.cpp @@ -1502,5 +1502,14 @@ void LogicSnapshot::free_head_blocks(int count) _lst_free_block_index = count; } +int LogicSnapshot::get_block_with_sample(uint64_t index, uint64_t *out_offset) +{ + assert(out_offset); + + int block = index / LeafBlockSamples; + *out_offset = index % LeafBlockSamples; + return block; +} + } // namespace data } // namespace pv diff --git a/DSView/pv/data/logicsnapshot.h b/DSView/pv/data/logicsnapshot.h index 91741301..32b7f635 100644 --- a/DSView/pv/data/logicsnapshot.h +++ b/DSView/pv/data/logicsnapshot.h @@ -150,6 +150,8 @@ public: return _loop_offset; } + static int get_block_with_sample(uint64_t index, uint64_t *out_offset); + private: bool get_sample_unlock(uint64_t index, int sig_index); bool get_sample_self(uint64_t index, int sig_index); diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index 032ad6f0..83d8d764 100644 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -28,10 +28,14 @@ #include #include #include +#include +#include #include "../ui/msgbox.h" #include "../config/appconfig.h" #include "../interface/icallbacks.h" #include "../log.h" +#include "../view/view.h" +#include "../view/cursor.h" #include "../ui/langresource.h" @@ -54,6 +58,10 @@ StoreProgress::StoreProgress(SigSession *session, QWidget *parent) : _isExport = false; _done = false; _isBusy = false; + _start_cursor = NULL; + _end_cursor = NULL; + _view = NULL; + _is_normal_end = false; QGridLayout *grid = new QGridLayout(); _grid = grid; @@ -104,8 +112,8 @@ StoreProgress::~StoreProgress() _store_session.wait(); } - void StoreProgress::on_change_file() - { +void StoreProgress::on_change_file() +{ QString file = ""; if (_isExport) file = _store_session.MakeExportFile(true); @@ -121,7 +129,7 @@ StoreProgress::~StoreProgress() _ckCompress->setVisible(bFlag); } } - } +} void StoreProgress::reject() { @@ -164,6 +172,47 @@ void StoreProgress::accept() } } + // Get data range + if (_store_session.IsLogicDataType() && _view != NULL) + { + uint64_t start_index = 0; + uint64_t end_index = 0; + + auto &cursor_list = _view->get_cursorList(); + + int dex1 = _start_cursor->currentIndex(); + int dex2 = _end_cursor->currentIndex(); + + if (dex1 > 0) + { + auto c = _view->get_cursor_by_index(dex1-1); + assert(c); + start_index = c->get_index(); + } + + if (dex2 > 0){ + auto c = _view->get_cursor_by_index(dex2-1); + assert(c); + end_index = c->get_index(); + } + + if (dex1 > 0 && dex2 > 0) + { + if (dex1 == dex2){ + QString mStr = L_S(STR_PAGE_MSG, S_ID(IDS_MSG_DATA_RANGE_ERROR), "Data range error"); + MsgBox::Show(mStr); + return; + } + else if (start_index > end_index){ + uint64_t tmp = start_index; + start_index = end_index; + end_index = tmp; + } + } + + _store_session.SetDataRange(start_index, end_index); + } + //start done if (_isExport){ if (_store_session.export_start()){ @@ -178,8 +227,8 @@ void StoreProgress::accept() show_error(); } } - else{ - if (_store_session.save_start()){ + else{ + if (_store_session.save_start()){ _isBusy = true; _store_session.session()->set_saving(true); QTimer::singleShot(100, this, SLOT(timeout())); @@ -214,6 +263,32 @@ void StoreProgress::save_run(ISessionDataGetter *getter) QString file = _store_session.MakeSaveFile(false); _fileLab->setText(file); _store_session._sessionDataGetter = getter; + + if (_store_session.IsLogicDataType() && _view != NULL) + { + QFormLayout *lay = new QFormLayout(); + lay->setContentsMargins(5, 0, 0, 0); + _start_cursor = new QComboBox(); + _end_cursor = new QComboBox(); + + _start_cursor->addItem("-"); + _end_cursor->addItem("-"); + + auto &cursor_list = _view->get_cursorList(); + + for (int i=0; iaddItem(cursor_name); + _end_cursor->addItem(cursor_name); + } + + lay->addRow(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_START_CURSOR), "Start") , _start_cursor); + lay->addRow(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_END_CURSOR), "End"), _end_cursor); + _grid->addLayout(lay, 2, 0, 1, 2); + } + show(); } @@ -221,7 +296,7 @@ void StoreProgress::export_run() { if (_store_session.IsLogicDataType()) { - QGridLayout *lay = new QGridLayout(); + QFormLayout *lay = new QFormLayout(); lay->setContentsMargins(5, 0, 0, 0); bool isOrg = AppConfig::Instance().appOptions.originalData; @@ -233,8 +308,31 @@ void StoreProgress::export_run() _ckCompress->setText(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_COMPRESSED_DATA), "Compressed data")); _ckCompress->setChecked(!isOrg); - lay->addWidget(_ckOrigin); - lay->addWidget(_ckCompress); + _start_cursor = new QComboBox(); + _end_cursor = new QComboBox(); + + _start_cursor->addItem("-"); + _end_cursor->addItem("-"); + + auto &cursor_list = _view->get_cursorList(); + + for (int i=0; iaddItem(cursor_name); + _end_cursor->addItem(cursor_name); + } + + lay->addRow(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_START_CURSOR), "Start") , _start_cursor); + lay->addRow(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_END_CURSOR), "End"), _end_cursor); + + QWidget *space = new QWidget(); + space->setFixedHeight(5); + lay->addRow(space); + + lay->addRow("",_ckOrigin); + lay->addRow("", _ckCompress); _grid->addLayout(lay, 2, 0, 1, 2); connect(_ckOrigin, SIGNAL(clicked(bool)), this, SLOT(on_ck_origin(bool))); @@ -246,11 +344,11 @@ void StoreProgress::export_run() QString file = _store_session.MakeExportFile(false); _fileLab->setText(file); - if (_ckOrigin != NULL){ - bool bFlag = file.endsWith(".csv"); - _ckOrigin->setVisible(bFlag); - _ckCompress->setVisible(bFlag); - } + if (_ckOrigin != NULL){ + bool bFlag = file.endsWith(".csv"); + _ckOrigin->setVisible(bFlag); + _ckCompress->setVisible(bFlag); + } show(); } @@ -265,26 +363,38 @@ void StoreProgress::show_error() void StoreProgress::closeEvent(QCloseEvent* e) { - _store_session.cancel(); + if (!_is_normal_end){ + _store_session.cancel(); + } + _store_session.session()->set_saving(false); - DSDialog::closeEvent(e); + save_done(); _store_session.session()->broadcast_msg(DSV_MSG_SAVE_COMPLETE); } void StoreProgress::on_progress_updated() { - const std::pair p = _store_session.progress(); - assert(p.first <= p.second); - int percent = p.first * 1.0 / p.second * 100; - _progress.setValue(percent); + uint64_t writed = 0; + uint64_t total = 0; + + _store_session.get_progress(&writed, &total); + + if (writed < total){ + int percent = writed * 1.0 / total * 100.0; + _progress.setValue(percent); + } + else{ + _progress.setValue(100); + } const QString err = _store_session.error(); if (!err.isEmpty()) { show_error(); } - if (p.first == p.second) { - _done = true; + if (writed >= total){ + _is_normal_end = true; + _done = true; // Set end flag. } } diff --git a/DSView/pv/dialogs/storeprogress.h b/DSView/pv/dialogs/storeprogress.h index a519135b..e6381c01 100644 --- a/DSView/pv/dialogs/storeprogress.h +++ b/DSView/pv/dialogs/storeprogress.h @@ -33,6 +33,13 @@ class QRadioButton; class QGridLayout; class QPushButton; class QWidget; +class QComboBox; + +namespace pv { + namespace view { + class View; + } +} namespace pv { @@ -50,6 +57,9 @@ public: virtual ~StoreProgress(); + inline void SetView(view::View *view){ + _view = view; + } protected: void reject(); @@ -85,6 +95,11 @@ private: QGridLayout *_grid; QWidget *_space; bool _isBusy; + QComboBox *_start_cursor; + QComboBox *_end_cursor; + view::View *_view; + bool _is_normal_end; + }; } // dialogs diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 0f50dac8..76aef535 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -626,6 +626,7 @@ namespace pv _session->set_saving(true); StoreProgress *dlg = new StoreProgress(_session, this); + dlg->SetView(_view); dlg->save_run(this); } @@ -639,6 +640,7 @@ namespace pv } StoreProgress *dlg = new StoreProgress(_session, this); + dlg->SetView(_view); dlg->export_run(); } diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 94364a97..0b3248e5 100644 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -75,6 +75,8 @@ StoreSession::StoreSession(SigSession *session) : _canceled(false) { _sessionDataGetter = NULL; + _start_index = 0; + _end_index = 0; } StoreSession::~StoreSession() @@ -87,9 +89,13 @@ SigSession* StoreSession::session() return _session; } -std::pair StoreSession::progress() -{ - return std::make_pair(_units_stored, _unit_count); +void StoreSession::get_progress(uint64_t *writed, uint64_t *total) +{ + assert(writed); + assert(total); + + *writed = _units_stored; + *total = _unit_count; } const QString& StoreSession::error() @@ -226,6 +232,40 @@ void StoreSession::save_logic(pv::data::LogicSnapshot *logic_snapshot) _unit_count = logic_snapshot->get_ring_sample_count() / 8 * to_save_probes; num = logic_snapshot->get_block_num(); + uint64_t start_index = _start_index; + uint64_t end_index = _end_index; + uint64_t start_offset = 0; + uint64_t end_offset = 0; + int start_block = 0; + int end_block = 0; + + if (start_index > logic_snapshot->get_ring_sample_count()){ + dsv_err("ERROR:the start curosr is invalid!"); + _units_stored = -1; + progress_updated(); + return; + } + if (end_index > logic_snapshot->get_ring_sample_count()){ + end_index = 0; + } + + if (start_index > 0){ + start_block = LogicSnapshot::get_block_with_sample(start_index, &start_offset); + } + if (end_index > 0){ + end_block = LogicSnapshot::get_block_with_sample(end_index, &end_offset); + } + + if (start_index > 0 && end_index > 0){ + _unit_count = (end_index - start_index) / 8 * to_save_probes; + } + else if (start_index > 0){ + _unit_count = (logic_snapshot->get_ring_sample_count() - start_index) / 8 * to_save_probes; + } + else if (end_index > 0){ + _unit_count = end_index / 8 * to_save_probes; + } + for(auto s : _session->get_signals()) { int ch_type = s->get_type(); @@ -234,7 +274,15 @@ void StoreSession::save_logic(pv::data::LogicSnapshot *logic_snapshot) if (!s->enabled() || !logic_snapshot->has_data(ch_index)) continue; - for (int i = 0; !_canceled && i < num; i++) { + for (int i = 0; !_canceled && i < num; i++) + { + if (i < start_block){ + continue; + } + if (i > end_block && end_block > 0){ + break; + } + uint8_t *buf = logic_snapshot->get_block_buf(i, ch_index, sample); uint64_t size = logic_snapshot->get_block_size(i); bool need_malloc = (buf == NULL); @@ -250,7 +298,7 @@ void StoreSession::save_logic(pv::data::LogicSnapshot *logic_snapshot) } } - MakeChunkName(chunk_name, i, ch_index, ch_type, HEADER_FORMAT_VERSION); + MakeChunkName(chunk_name, i - start_block, ch_index, ch_type, HEADER_FORMAT_VERSION); ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)buf, size) ? SR_OK : -1; if (ret != SR_OK) { @@ -266,7 +314,9 @@ void StoreSession::save_logic(pv::data::LogicSnapshot *logic_snapshot) } _units_stored += size; - if (_units_stored > _unit_count){ + if (_units_stored > _unit_count + && start_index == 0 + && end_index == 0){ dsv_err("Read block data error!"); assert(false); } @@ -494,8 +544,38 @@ bool StoreSession::meta_gen(data::Snapshot *snapshot, std::string &str) if (probe->enabled && logic_snapshot->has_data(probe->index)) to_save_probes++; } + + int block_count = logic_snapshot->get_block_num(); + + uint64_t start_index = _start_index; + uint64_t end_index = _end_index; + uint64_t start_offset = 0; + uint64_t end_offset = 0; + int start_block = 0; + int end_block = 0; + + if (end_index > logic_snapshot->get_ring_sample_count()){ + end_index = 0; + } + if (start_index > 0){ + start_block = LogicSnapshot::get_block_with_sample(start_index, &start_offset); + } + if (end_index > 0){ + end_block = LogicSnapshot::get_block_with_sample(end_index, &end_offset); + } + + if (start_index > 0 && end_index > 0){ + block_count = end_block - start_block + 1; + } + else if (start_index > 0){ + block_count = block_count - start_block; + } + else if (end_index > 0){ + block_count = end_block + 1; + } + sprintf(meta, "total probes = %d\n", to_save_probes); str += meta; - sprintf(meta, "total blocks = %d\n", logic_snapshot->get_block_num()); str += meta; + sprintf(meta, "total blocks = %d\n", block_count); str += meta; } s = sr_samplerate_string(_session->cur_snap_samplerate()); @@ -775,6 +855,11 @@ void StoreSession::export_proc(data::Snapshot *snapshot) output.module = (sr_output_module*) _outModule; output.sdi = _session->get_device()->inst(); output.param = NULL; + output.start_sample_index = 0; + + if (channel_type == SR_CHANNEL_LOGIC){ + output.start_sample_index = _start_index; + } if(_outModule->init){ if(_outModule->init(&output, params) != SR_OK){ @@ -854,11 +939,50 @@ void StoreSession::export_proc(data::Snapshot *snapshot) std::vector buf_vec; std::vector buf_sample; + uint64_t start_index = _start_index; + uint64_t end_index = _end_index; + uint64_t start_offset = 0; + uint64_t end_offset = 0; + int start_block = 0; + int end_block = 0; + + if (start_index > logic_snapshot->get_ring_sample_count()){ + dsv_err("ERROR:the start curosr is invalid!"); + _units_stored = -1; + progress_updated(); + return; + } + if (end_index > logic_snapshot->get_ring_sample_count()){ + end_index = 0; + } + + if (start_index > 0){ + start_block = LogicSnapshot::get_block_with_sample(start_index, &start_offset); + } + if (end_index > 0){ + end_block = LogicSnapshot::get_block_with_sample(end_index, &end_offset); + } + + if (start_index > 0 && end_index > 0){ + _unit_count = (end_index - start_index); + } + else if (start_index > 0){ + _unit_count = (logic_snapshot->get_ring_sample_count() - start_index); + } + else if (end_index > 0){ + _unit_count = end_index; + } + for (int blk = 0; !_canceled && blk < blk_num; blk++) { uint64_t buf_sample_num = logic_snapshot->get_block_size(blk) * 8; buf_vec.clear(); buf_sample.clear(); + if (blk < start_block) + continue; + if (blk > end_block && end_block > 0) + break; + for(auto s : _session->get_signals()) { int ch_type = s->get_type(); if (ch_type == SR_CHANNEL_LOGIC) { diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 67974edf..d247ebd9 100644 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -59,7 +59,7 @@ public: SigSession* session(); - std::pair progress(); + void get_progress(uint64_t *writed, uint64_t *total); const QString& error(); @@ -91,7 +91,11 @@ public: { return _file_name;} bool IsLogicDataType(); - + + inline void SetDataRange(uint64_t start_index, uint64_t end_index){ + _start_index = start_index; + _end_index = end_index; + } private: QList getSuportedExportFormats(); @@ -119,6 +123,8 @@ private: QString _error; volatile bool _canceled; ZipMaker m_zipDoc; + uint64_t _start_index; + uint64_t _end_index; }; } // pv diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 5b274317..659a8405 100644 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -1408,5 +1408,19 @@ bool View::header_is_draging() return _header->mouse_is_down(); } +Cursor* View::get_cursor_by_index(int index) +{ + int dex = 0; + auto &cursors = get_cursorList(); + + for (auto c : cursors){ + if (dex == index){ + return c; + } + dex++; + } + return NULL; +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index 8c281a8e..70942e61 100644 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -229,6 +229,8 @@ public: return _trig_cursor; } + Cursor* get_cursor_by_index(int index); + inline Cursor* get_search_cursor(){ return _search_cursor; } diff --git a/lang/cn/dlg.json b/lang/cn/dlg.json index 10991ae8..affdd043 100644 --- a/lang/cn/dlg.json +++ b/lang/cn/dlg.json @@ -722,5 +722,13 @@ { "id": "IDS_DLG_DATA_OUT_OFF_RANGE", "text": "数据超出量程" - } + }, + { + "id": "IDS_DLG_START_CURSOR", + "text": "开始" + }, + { + "id": "IDS_DLG_END_CURSOR", + "text": "结束" + } ] diff --git a/lang/cn/msg.json b/lang/cn/msg.json index f67e4620..8d0c1ef6 100644 --- a/lang/cn/msg.json +++ b/lang/cn/msg.json @@ -377,5 +377,9 @@ { "id": "IDS_MSG_DEVICE_USB_IO_ERROR", "text": "Error: USB读写错误!" + }, + { + "id": "IDS_MSG_DATA_RANGE_ERROR", + "text": "数据范围设置错误!" } ] diff --git a/lang/en/dlg.json b/lang/en/dlg.json index b8193acf..4196a2e2 100644 --- a/lang/en/dlg.json +++ b/lang/en/dlg.json @@ -722,5 +722,13 @@ { "id": "IDS_DLG_DATA_OUT_OFF_RANGE", "text": "Data out off range" + }, + { + "id": "IDS_DLG_START_CURSOR", + "text": "Start" + }, + { + "id": "IDS_DLG_END_CURSOR", + "text": "End" } ] diff --git a/lang/en/msg.json b/lang/en/msg.json index 373b4ff5..b4eb92e0 100644 --- a/lang/en/msg.json +++ b/lang/en/msg.json @@ -378,5 +378,9 @@ { "id": "IDS_MSG_DEVICE_USB_IO_ERROR", "text": "Error: USB IO error!" + }, + { + "id": "IDS_MSG_DATA_RANGE_ERROR", + "text": "Data range is error!" } ] diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index a2b470cf..e8f6b15d 100644 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -530,6 +530,8 @@ struct sr_output { * there, and only flush it when it reaches a certain size. */ void *priv; + + uint64_t start_sample_index; }; /** Generic option struct used by various subsystems. */ diff --git a/libsigrok4DSL/output/csv.c b/libsigrok4DSL/output/csv.c index c9fc4b67..82e06f88 100644 --- a/libsigrok4DSL/output/csv.c +++ b/libsigrok4DSL/output/csv.c @@ -88,6 +88,10 @@ static int init(struct sr_output *o, GHashTable *options) ctx->type = g_variant_get_int16(g_hash_table_lookup(options, "type")); ch_num = 0; + if (o->start_sample_index > 0){ + ctx->index = o->start_sample_index; + } + /* Get the number of channels, and the unitsize. */ for (l = o->sdi->channels; l; l = l->next) { ch = l->data; diff --git a/libsigrok4DSL/session_driver.c b/libsigrok4DSL/session_driver.c index 6da4b024..e479e2b7 100644 --- a/libsigrok4DSL/session_driver.c +++ b/libsigrok4DSL/session_driver.c @@ -636,6 +636,7 @@ static int receive_data_logic_dso_v2(int fd, int revents, const struct sr_dev_in if ((pack_buffer->block_data_len - pack_buffer->block_read_len) % 8 != 0) { sr_err("The block data is not align with 8 byte."); + bToEnd = 1; break; } }