diff --git a/DSView/DSView.qrc b/DSView/DSView.qrc index 76bf2800..5968cc45 100644 --- a/DSView/DSView.qrc +++ b/DSView/DSView.qrc @@ -57,5 +57,16 @@ icons/start_dis_cn.png icons/settings.png darkstyle/style.qss + icons/export.png + icons/single.png + icons/single_dis.png + icons/math.png + icons/math_dis.png + icons/fft.png + icons/Blackman.png + icons/Flat_top.png + icons/Hamming.png + icons/Hann.png + icons/Rectangle.png diff --git a/DSView/extdef.h b/DSView/extdef.h index 549c0629..192bb8f3 100644 --- a/DSView/extdef.h +++ b/DSView/extdef.h @@ -29,4 +29,10 @@ #define begin_element(x) (&x[0]) #define end_element(x) (&x[countof(x)]) +enum View_type { + TIME_VIEW, + FFT_VIEW, + ALL_VIEW +}; + #endif // DSVIEW_EXTDEF_H diff --git a/DSView/icons/about.png b/DSView/icons/about.png old mode 100644 new mode 100755 index ac389095..c8f40c62 Binary files a/DSView/icons/about.png and b/DSView/icons/about.png differ diff --git a/DSView/icons/export.png b/DSView/icons/export.png index cd319389..57ee72ff 100755 Binary files a/DSView/icons/export.png and b/DSView/icons/export.png differ diff --git a/DSView/icons/file.png b/DSView/icons/file.png old mode 100644 new mode 100755 index 2a4715da..78c469cc Binary files a/DSView/icons/file.png and b/DSView/icons/file.png differ diff --git a/DSView/icons/file_dis.png b/DSView/icons/file_dis.png old mode 100644 new mode 100755 index 65373110..5c27e1ae Binary files a/DSView/icons/file_dis.png and b/DSView/icons/file_dis.png differ diff --git a/DSView/icons/instant.png b/DSView/icons/instant.png old mode 100644 new mode 100755 index 2aa5c250..c3e249d3 Binary files a/DSView/icons/instant.png and b/DSView/icons/instant.png differ diff --git a/DSView/icons/instant_dis.png b/DSView/icons/instant_dis.png index e3f8adfc..9c24bf07 100755 Binary files a/DSView/icons/instant_dis.png and b/DSView/icons/instant_dis.png differ diff --git a/DSView/icons/math.png b/DSView/icons/math.png index 59f7c5f4..dbb83a78 100755 Binary files a/DSView/icons/math.png and b/DSView/icons/math.png differ diff --git a/DSView/icons/math_dis.png b/DSView/icons/math_dis.png index 40212085..9850dd5e 100755 Binary files a/DSView/icons/math_dis.png and b/DSView/icons/math_dis.png differ diff --git a/DSView/icons/measure.png b/DSView/icons/measure.png old mode 100644 new mode 100755 index c858a50d..461bb7c9 Binary files a/DSView/icons/measure.png and b/DSView/icons/measure.png differ diff --git a/DSView/icons/measure_dis.png b/DSView/icons/measure_dis.png old mode 100644 new mode 100755 index 8510560a..3f152eee Binary files a/DSView/icons/measure_dis.png and b/DSView/icons/measure_dis.png differ diff --git a/DSView/icons/params.png b/DSView/icons/params.png old mode 100644 new mode 100755 index ea7c1a0e..d6a9fff7 Binary files a/DSView/icons/params.png and b/DSView/icons/params.png differ diff --git a/DSView/icons/params_dis.png b/DSView/icons/params_dis.png old mode 100644 new mode 100755 index 277a3266..af2518a7 Binary files a/DSView/icons/params_dis.png and b/DSView/icons/params_dis.png differ diff --git a/DSView/icons/protocol.png b/DSView/icons/protocol.png old mode 100644 new mode 100755 index 91423ec2..acf434e2 Binary files a/DSView/icons/protocol.png and b/DSView/icons/protocol.png differ diff --git a/DSView/icons/protocol_cn.png b/DSView/icons/protocol_cn.png old mode 100644 new mode 100755 index 213fd151..f1af4fec Binary files a/DSView/icons/protocol_cn.png and b/DSView/icons/protocol_cn.png differ diff --git a/DSView/icons/protocol_dis.png b/DSView/icons/protocol_dis.png old mode 100644 new mode 100755 index b5278b68..3836866f Binary files a/DSView/icons/protocol_dis.png and b/DSView/icons/protocol_dis.png differ diff --git a/DSView/icons/search-bar.png b/DSView/icons/search-bar.png old mode 100644 new mode 100755 index 20b94274..1e58096d Binary files a/DSView/icons/search-bar.png and b/DSView/icons/search-bar.png differ diff --git a/DSView/icons/search-bar_dis.png b/DSView/icons/search-bar_dis.png old mode 100644 new mode 100755 index a19d5834..1b2d6955 Binary files a/DSView/icons/search-bar_dis.png and b/DSView/icons/search-bar_dis.png differ diff --git a/DSView/icons/start.png b/DSView/icons/start.png old mode 100644 new mode 100755 index bd42b602..4c2d7e61 Binary files a/DSView/icons/start.png and b/DSView/icons/start.png differ diff --git a/DSView/icons/start_dis.png b/DSView/icons/start_dis.png index 62eee6d5..56f6e901 100755 Binary files a/DSView/icons/start_dis.png and b/DSView/icons/start_dis.png differ diff --git a/DSView/icons/stop.png b/DSView/icons/stop.png old mode 100644 new mode 100755 index 969a6999..77aa105d Binary files a/DSView/icons/stop.png and b/DSView/icons/stop.png differ diff --git a/DSView/icons/trigger.png b/DSView/icons/trigger.png old mode 100644 new mode 100755 index 5f8f4965..6b1ca1b8 Binary files a/DSView/icons/trigger.png and b/DSView/icons/trigger.png differ diff --git a/DSView/icons/trigger_dis.png b/DSView/icons/trigger_dis.png old mode 100644 new mode 100755 index 9c804d0e..eb401cff Binary files a/DSView/icons/trigger_dis.png and b/DSView/icons/trigger_dis.png differ diff --git a/DSView/icons/wiki.png b/DSView/icons/wiki.png old mode 100644 new mode 100755 index 4515019c..8e06ac1d Binary files a/DSView/icons/wiki.png and b/DSView/icons/wiki.png differ diff --git a/DSView/pv/data/mathstack.cpp b/DSView/pv/data/mathstack.cpp index e525b42a..99e3e0b4 100644 --- a/DSView/pv/data/mathstack.cpp +++ b/DSView/pv/data/mathstack.cpp @@ -1,7 +1,241 @@ -#include "fftstack.h" +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "mathstack.h" -FftStack::FftStack() +#include +#include + +#include +#include +#include +#include + +#define PI 3.1415 + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +const QString MathStack::windows_support[5] = { + "Rectangle", + "Hann", + "Hamming", + "Blackman", + "Flat_top" +}; + +const uint64_t MathStack::length_support[5] = { + 1024, + 2048, + 4096, + 8192, + 16384, +}; + +MathStack::MathStack(pv::SigSession &session, int index) : + _session(session), + _index(index), + _dc_ignore(true), + _sample_interval(1), + _math_state(Init) +{ +} + +MathStack::~MathStack() +{ + _xn.clear(); + _xk.clear(); + _power_spectrum.clear(); + fftw_destroy_plan(_fft_plan); +} + +void MathStack::clear() { } +int MathStack::get_index() const +{ + return _index; +} + +uint64_t MathStack::get_sample_num() const +{ + return _sample_num; +} + +void MathStack::set_sample_num(uint64_t num) +{ + _sample_num = num; + _xn.resize(_sample_num); + _xk.resize(_sample_num); + _power_spectrum.resize(_sample_num/2+1); + _fft_plan = fftw_plan_r2r_1d(_sample_num, _xn.data(), _xk.data(), + FFTW_R2HC, FFTW_ESTIMATE); +} + +int MathStack::get_windows_index() const +{ + return _windows_index; +} + +void MathStack::set_windows_index(int index) +{ + _windows_index = index; +} + +bool MathStack::dc_ignored() const +{ + return _dc_ignore; +} + +void MathStack::set_dc_ignore(bool ignore) +{ + _dc_ignore = ignore; +} + +int MathStack::get_sample_interval() const +{ + return _sample_interval; +} + +void MathStack::set_sample_interval(int interval) +{ + _sample_interval = interval; +} + +const std::vector MathStack::get_windows_support() const +{ + std::vector windows; + for (size_t i = 0; i < sizeof(windows_support)/sizeof(windows_support[0]); i++) + { + windows.push_back(windows_support[i]); + } + return windows; +} + +const std::vector MathStack::get_length_support() const +{ + std::vector length; + for (size_t i = 0; i < sizeof(length_support)/sizeof(length_support[0]); i++) + { + length.push_back(length_support[i]); + } + return length; +} + +const std::vector MathStack::get_fft_spectrum() const +{ + std::vector empty; + if (_math_state == Stopped) + return _power_spectrum; + else + return empty; +} + +const double MathStack::get_fft_spectrum(uint64_t index) const +{ + if (_math_state == Stopped && index < _power_spectrum.size()) + return _power_spectrum[index]; + else + return -1; +} + +void MathStack::calc_fft() +{ + _math_state = Running; + // Get the dso data + boost::shared_ptr data; + boost::shared_ptr dsoSig; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_index() == _index && dsoSig->enabled()) { + data = dsoSig->dso_data(); + break; + } + } + } + + if (!data) + return; + + // Check we have a snapshot of data + const deque< boost::shared_ptr > &snapshots = + data->get_snapshots(); + if (snapshots.empty()) + return; + _snapshot = snapshots.front(); + + if (_snapshot->get_sample_count() < _sample_num*_sample_interval) + return; + + // Get the samplerate and start time + _start_time = data->get_start_time(); + _samplerate = data->samplerate(); + if (_samplerate == 0.0) + _samplerate = 1.0; + + // prepare _xn data + const double offset = dsoSig->get_zeroValue(); + const double vscale = dsoSig->get_vDialValue() * dsoSig->get_factor() * DS_CONF_DSO_VDIVS / (1000*255.0); + const uint16_t step = _snapshot->get_channel_num() * _sample_interval; + const uint8_t *const samples = _snapshot->get_samples(0, _sample_num*_sample_interval-1, _index); + double wsum = 0; + for (int i = 0; i < _sample_num; i++) { + double w = window(i, _windows_index); + _xn[i] = ((double)samples[i*step] - offset) * vscale * w; + wsum += w; + } + + // fft + fftw_execute(_fft_plan); + + // calculate power spectrum + _power_spectrum[0] = abs(_xk[0])/wsum; /* DC component */ + for (int k = 1; k < (_sample_num + 1) / 2; ++k) /* (k < N/2 rounded up) */ + _power_spectrum[k] = sqrt((_xk[k]*_xk[k] + _xk[_sample_num-k]*_xk[_sample_num-k]) * 2) / wsum; + if (_sample_num % 2 == 0) /* N is even */ + _power_spectrum[_sample_num/2] = abs(_xk[_sample_num/2])/wsum; /* Nyquist freq. */ + + _math_state = Stopped; +} + +double MathStack::window(uint64_t i, int type) +{ + const double n_m_1 = _sample_num-1; + switch(type) { + case 1: // Hann window + return 0.5*(1-cos(2*PI*i/n_m_1)); + case 2: // Hamming window + return 0.54-0.46*cos(2*PI*i/n_m_1); + case 3: // Blackman window + return 0.42659-0.49656*cos(2*PI*i/n_m_1) + 0.076849*cos(4*PI*i/n_m_1); + case 4: // Flat_top window + return 1-1.93*cos(2*PI*i/n_m_1)+1.29*cos(4*PI*i/n_m_1)- + 0.388*cos(6*PI*i/n_m_1)+0.028*cos(8*PI*i/n_m_1); + default: + return 1; + } +} + +} // namespace data +} // namespace pv diff --git a/DSView/pv/data/mathstack.h b/DSView/pv/data/mathstack.h index c1449463..dbbe21bc 100644 --- a/DSView/pv/data/mathstack.h +++ b/DSView/pv/data/mathstack.h @@ -1,11 +1,119 @@ -#ifndef FFTSTACK_H -#define FFTSTACK_H +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef DSVIEW_PV_DATA_MATHSTACK_H +#define DSVIEW_PV_DATA_MATHSTACK_H -class FftStack +#include "signaldata.h" + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace pv { + +class SigSession; + +namespace view { +class DsoSignal; +} + +namespace data { + +class DsoSnapshot; +class Dso; + +class MathStack : public QObject, public SignalData { + Q_OBJECT + +private: + static const QString windows_support[5]; + static const uint64_t length_support[5]; + public: - FftStack(); + enum math_state { + Init, + Stopped, + Running + }; + +public: + MathStack(pv::SigSession &_session, int index); + virtual ~MathStack(); + void clear(); + + int get_index() const; + + uint64_t get_sample_num() const; + void set_sample_num(uint64_t num); + + int get_windows_index() const; + void set_windows_index(int index); + + const std::vector get_windows_support() const; + const std::vector get_length_support() const; + + bool dc_ignored() const; + void set_dc_ignore(bool ignore); + + int get_sample_interval() const; + void set_sample_interval(int interval); + + const std::vector get_fft_spectrum() const; + const double get_fft_spectrum(uint64_t index) const; + + void calc_fft(); + + double window(uint64_t i, int type); + +signals: + +private: + pv::SigSession &_session; + + int _index; + uint64_t _sample_num; + int _windows_index; + bool _dc_ignore; + int _sample_interval; + + boost::shared_ptr _snapshot; + + std::unique_ptr _math_thread; + math_state _math_state; + + fftw_plan _fft_plan; + std::vector _xn; + std::vector _xk; + std::vector _power_spectrum; }; -#endif // FFTSTACK_H +} // namespace data +} // namespace pv + +#endif // DSVIEW_PV_DATA_MATHSTACK_H diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index 576975c3..b73ac46e 100644 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -1,7 +1,257 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + #include "fftoptions.h" -FftOptions::FftOptions() -{ +#include +#include +#include +#include + +#include "../sigsession.h" +#include "../data/mathstack.h" +#include "../view/trace.h" +#include "../view/dsosignal.h" +#include "../view/mathtrace.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +FftOptions::FftOptions(QWidget *parent, SigSession &session) : + QDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, this) +{ + _en_checkbox = new QCheckBox(this); + _len_combobox = new QComboBox(this); + _interval_combobox = new QComboBox(this); + _ch_combobox = new QComboBox(this); + _window_combobox = new QComboBox(this); + _dc_checkbox = new QCheckBox(this); + _dc_checkbox->setChecked(true); + _view_combobox = new QComboBox(this); + _dbv_combobox = new QComboBox(this); + + // setup _ch_combobox + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + _ch_combobox->addItem(dsoSig->get_name(), qVariantFromValue(dsoSig->get_index())); + } + } + + // setup _window_combobox _len_combobox + _sample_limit = 0; + GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLELIMITS); + if (gvar != NULL) { + _sample_limit = g_variant_get_uint64(gvar) * 0.5; + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_MAX_DSO_SAMPLELIMITS failed."; + } + std::vector windows; + std::vector length; + std::vector view_modes; + std::vector dbv_ranges; + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + windows = mathTrace->get_math_stack()->get_windows_support(); + length = mathTrace->get_math_stack()->get_length_support(); + view_modes = mathTrace->get_view_modes_support(); + dbv_ranges = mathTrace->get_dbv_ranges(); + break; + } + } + assert(windows.size() > 0); + assert(length.size() > 0); + assert(view_modes.size() > 0); + assert(dbv_ranges.size() > 0); + for (int i = 0; i < windows.size(); i++) + { + _window_combobox->addItem(windows[i], + qVariantFromValue(i)); + } + for (int i = 0; i < length.size(); i++) + { + if (length[i] < _sample_limit) + _len_combobox->addItem(QString::number(length[i]), + qVariantFromValue(length[i])); + else + break; + } + assert(_len_combobox->count() > 0); + _len_combobox->setCurrentIndex(_len_combobox->count()-1); + + const int max_interval = _sample_limit/_len_combobox->currentData().toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + for (int i = 0; i < view_modes.size(); i++) + { + _view_combobox->addItem(view_modes[i], + qVariantFromValue(i)); + } + for (int i = 0; i < dbv_ranges.size(); i++) + { + _dbv_combobox->addItem(QString::number(dbv_ranges[i]), + qVariantFromValue(dbv_ranges[i])); + } + + // load current settings + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + if (mathTrace->enabled()) { + _en_checkbox->setChecked(true); + for (int i = 0; i < _ch_combobox->count(); i++) { + if (mathTrace->get_index() == _ch_combobox->itemData(i).toInt()) { + _ch_combobox->setCurrentIndex(i); + break; + } + } + for (int i = 0; i < _len_combobox->count(); i++) { + if (mathTrace->get_math_stack()->get_sample_num() == _len_combobox->itemData(i).toLongLong()) { + _len_combobox->setCurrentIndex(i); + break; + } + } + _interval_combobox->clear(); + const int max_interval = _sample_limit/_len_combobox->currentData().toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + for (int i = 0; i < _interval_combobox->count(); i++) { + if (mathTrace->get_math_stack()->get_sample_interval() == _interval_combobox->itemData(i).toInt()) { + _interval_combobox->setCurrentIndex(i); + break; + } + } + for (int i = 0; i < _dbv_combobox->count(); i++) { + if (mathTrace->dbv_range() == _dbv_combobox->itemData(i).toLongLong()) { + _dbv_combobox->setCurrentIndex(i); + break; + } + } + _window_combobox->setCurrentIndex(mathTrace->get_math_stack()->get_windows_index()); + _dc_checkbox->setChecked(mathTrace->get_math_stack()->dc_ignored()); + _view_combobox->setCurrentIndex(mathTrace->view_mode()); + } + } + } + + _flayout = new QFormLayout(); + _flayout->addRow(new QLabel(tr("FFT Enable: "), this), _en_checkbox); + _flayout->addRow(new QLabel(tr("FFT Length: "), this), _len_combobox); + _flayout->addRow(new QLabel(tr("Sample Interval: "), this), _interval_combobox); + _flayout->addRow(new QLabel(tr("FFT Source: "), this), _ch_combobox); + _flayout->addRow(new QLabel(tr("FFT Window: "), this), _window_combobox); + _flayout->addRow(new QLabel(tr("DC Ignored: "), this), _dc_checkbox); + _flayout->addRow(new QLabel(tr("Y-axis Mode: "), this), _view_combobox); + _flayout->addRow(new QLabel(tr("DBV Range: "), this), _dbv_combobox); + + _hlayout = new QHBoxLayout(); + _hlayout->addLayout(_flayout); + _hint_label = new QLabel(this); + QString hint_pic= ":/icons/" + _window_combobox->currentText()+".png"; + QPixmap pixmap(hint_pic); + _hint_label->setPixmap(pixmap); + _hlayout->addWidget(_hint_label); + + _layout = new QVBoxLayout(this); + _layout->addLayout(_hlayout); + _layout->addWidget(&_button_box); + setLayout(_layout); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(_window_combobox, SIGNAL(currentIndexChanged(QString)), this, SLOT(window_changed(QString))); + connect(_len_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(len_changed(int))); } +void FftOptions::accept() +{ + using namespace Qt; + + QDialog::accept(); + + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + mathTrace->set_enable(false); + if (mathTrace->get_index() == _ch_combobox->currentData().toInt()) { + mathTrace->get_math_stack()->set_dc_ignore(_dc_checkbox->isChecked()); + mathTrace->get_math_stack()->set_sample_num(_len_combobox->currentData().toULongLong()); + mathTrace->get_math_stack()->set_sample_interval(_interval_combobox->currentData().toInt()); + mathTrace->get_math_stack()->set_windows_index(_window_combobox->currentData().toInt()); + mathTrace->set_view_mode(_view_combobox->currentData().toInt()); + //mathTrace->init_zoom(); + mathTrace->set_dbv_range(_dbv_combobox->currentData().toInt()); + mathTrace->set_enable(_en_checkbox->isChecked()); + if (_session.get_capture_state() == SigSession::Stopped && + mathTrace->enabled()) + mathTrace->get_math_stack()->calc_fft(); + } + } + } + _session.mathTraces_rebuild(); +} + +void FftOptions::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +void FftOptions::window_changed(QString str) +{ + QString hint_pic= ":/icons/" + str +".png"; + QPixmap pixmap(hint_pic); + _hint_label->setPixmap(pixmap); +} + +void FftOptions::len_changed(int index) +{ + int pre_index = _interval_combobox->currentIndex(); + _interval_combobox->clear(); + const int max_interval = _sample_limit/_len_combobox->itemData(index).toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + _interval_combobox->setCurrentIndex(pre_index); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/fftoptions.h b/DSView/pv/dialogs/fftoptions.h index 618c0618..534ef3e0 100644 --- a/DSView/pv/dialogs/fftoptions.h +++ b/DSView/pv/dialogs/fftoptions.h @@ -1,11 +1,87 @@ -#ifndef FFTOPTIONS_H -#define FFTOPTIONS_H +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ -class FftOptions +#ifndef DSVIEW_PV_FFTOPTIONS_H +#define DSVIEW_PV_FFTOPTIONS_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../device/devinst.h" + +namespace pv { + +class SigSession; + +namespace dialogs { + +class FftOptions : public QDialog { + Q_OBJECT + +private: + + public: - FftOptions(); + FftOptions(QWidget *parent, SigSession &session); + +protected: + void accept(); + void reject(); + +private slots: + void window_changed(QString str); + void len_changed(int index); + +private: + SigSession &_session; + uint64_t _sample_limit; + + QComboBox *_len_combobox; + QComboBox *_interval_combobox; + QCheckBox *_en_checkbox; + QComboBox *_ch_combobox; + QComboBox *_window_combobox; + QCheckBox *_dc_checkbox; + QComboBox *_view_combobox; + QComboBox *_dbv_combobox; + + QLabel *_hint_label; + QFormLayout *_flayout; + QHBoxLayout *_hlayout; + QVBoxLayout *_layout; + QDialogButtonBox _button_box; + }; -#endif // FFTOPTIONS_H +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_FFTOPTIONS_H diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 6a329021..c49f0743 100644 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -134,7 +134,7 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); connect(_fen_checkBox, SIGNAL(stateChanged(int)), &_view, SLOT(set_measure_en(int))); - connect(_view.get_viewport(), SIGNAL(measure_updated()), this, SLOT(measure_updated())); + connect(&_view, SIGNAL(measure_updated()), this, SLOT(measure_updated())); this->setWidget(_widget); _widget->setGeometry(0, 0, sizeHint().width(), 2000); @@ -222,10 +222,10 @@ void MeasureDock::cursor_update() void MeasureDock::measure_updated() { - _width_label->setText(_view.get_viewport()->get_measure("width")); - _period_label->setText(_view.get_viewport()->get_measure("period")); - _freq_label->setText(_view.get_viewport()->get_measure("frequency")); - _duty_label->setText(_view.get_viewport()->get_measure("duty")); + _width_label->setText(_view.get_measure("width")); + _period_label->setText(_view.get_measure("period")); + _freq_label->setText(_view.get_measure("frequency")); + _duty_label->setText(_view.get_measure("duty")); } void MeasureDock::cursor_moved() diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 90417108..0806142a 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -112,6 +112,7 @@ void MainWindow::setup_ui() { setObjectName(QString::fromUtf8("MainWindow")); setMinimumHeight(680); + setMinimumWidth(300); resize(1024, 768); // Set the window icon @@ -129,7 +130,7 @@ void MainWindow::setup_ui() // Setup the sampling bar _sampling_bar = new toolbars::SamplingBar(_session, this); - _trig_bar = new toolbars::TrigBar(this); + _trig_bar = new toolbars::TrigBar(_session, this); _file_bar = new toolbars::FileBar(_session, this); _logo_bar = new toolbars::LogoBar(_session, this); @@ -295,18 +296,8 @@ void MainWindow::update_device_list() #ifdef ENABLE_DECODE _protocol_widget->del_all_protocol(); #endif - _trig_bar->close_all(); - - if (_session.get_device()->dev_inst()->mode == LOGIC) { - _trig_bar->enable_protocol(true); - } else { - _trig_bar->enable_protocol(false); - } - if (_session.get_device()->dev_inst()->mode == DSO) { - _sampling_bar->enable_toggle(false); - } else { - _sampling_bar->enable_toggle(true); - } + _trig_bar->reload(); + _sampling_bar->reload(); shared_ptr selected_device = _session.get_device(); _device_manager.add_device(selected_device); @@ -534,8 +525,7 @@ void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::on_protocol(bool visible) { #ifdef ENABLE_DECODE - if (_session.get_device()->dev_inst()->mode == LOGIC) - _protocol_dock->setVisible(visible); + _protocol_dock->setVisible(visible); #endif } diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 8b0802cf..e0b443df 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -42,12 +42,14 @@ #include "data/decoderstack.h" #include "data/decode/decoder.h" #include "data/decodermodel.h" +#include "data/mathstack.h" #include "view/analogsignal.h" #include "view/dsosignal.h" #include "view/logicsignal.h" #include "view/groupsignal.h" #include "view/decodetrace.h" +#include "view/mathtrace.h" #include #include @@ -496,7 +498,6 @@ set< boost::shared_ptr > SigSession::get_data() const assert(sig); data.insert(sig->data()); } - data.insert(_group_data); return data; } @@ -605,6 +606,12 @@ void SigSession::read_sample_rate(const sr_dev_inst *const sdi) assert(data); data->set_samplerate(sample_rate); } + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + m->get_math_stack()->set_samplerate(sample_rate); + } + _group_data->set_samplerate(sample_rate); } void SigSession::feed_in_header(const sr_dev_inst *sdi) @@ -791,10 +798,10 @@ void SigSession::init_signals() _signals.clear(); vector< boost::shared_ptr >().swap(_signals); _signals = sigs; - - signals_changed(); - data_updated(); } + + mathTraces_rebuild(); + data_updated(); } void SigSession::reload() @@ -854,7 +861,7 @@ void SigSession::reload() _signals = sigs; } - signals_changed(); + mathTraces_rebuild(); } void SigSession::refresh(int holdtime) @@ -1009,6 +1016,14 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) return; } + // reset scale of dso signal + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + if (m->enabled()) + m->get_math_stack()->calc_fft(); + } + receive_data(dso.num_samples); data_updated(); //if (!_instant) @@ -1401,7 +1416,41 @@ pv::data::DecoderModel* SigSession::get_decoder_model() const { return _decoder_model; } - #endif +void SigSession::mathTraces_rebuild() +{ + bool has_dso_signal = false; + BOOST_FOREACH(const boost::shared_ptr s, _signals) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + has_dso_signal = true; + // check already have + std::vector< boost::shared_ptr >::iterator iter = _math_traces.begin(); + for(int i = 0; i < _math_traces.size(); i++, iter++) + if ((*iter)->get_index() == dsoSig->get_index()) + break; + // if not, rebuild + if (iter == _math_traces.end()) { + boost::shared_ptr math_stack( + new data::MathStack(*this, dsoSig->get_index())); + boost::shared_ptr math_trace( + new view::MathTrace(*this, math_stack, dsoSig->get_index())); + _math_traces.push_back(math_trace); + } + } + } + + if (!has_dso_signal) + _math_traces.clear(); + + signals_changed(); +} + +vector< boost::shared_ptr > SigSession::get_math_signals() +{ + lock_guard lock(_signals_mutex); + return _math_traces; +} + } // namespace pv diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index de159f17..9005ab7f 100644 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -78,6 +78,7 @@ namespace view { class Signal; class GroupSignal; class DecodeTrace; +class MathTrace; } namespace decoder { @@ -157,6 +158,9 @@ public: pv::data::DecoderModel* get_decoder_model() const; + std::vector< boost::shared_ptr > + get_math_signals(); + #endif void init_signals(); @@ -178,6 +182,8 @@ public: bool get_data_lock(); + void mathTraces_rebuild(); + private: void set_capture_state(capture_state state); @@ -239,6 +245,7 @@ private: std::vector< boost::shared_ptr > _decode_traces; pv::data::DecoderModel *_decoder_model; #endif + std::vector< boost::shared_ptr > _math_traces; mutable boost::mutex _data_mutex; boost::shared_ptr _logic_data; diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 5562db7a..cd7e0d94 100644 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -96,7 +96,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_export = new QAction(this); _action_export->setText(QApplication::translate("File", "&Export...", 0)); - _action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/instant.png"))); + _action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/export.png"))); _action_export->setObjectName(QString::fromUtf8("actionExport")); connect(_action_export, SIGNAL(triggered()), this, SLOT(on_actionExport_triggered())); diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index ed758736..466e382d 100644 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -154,8 +154,8 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : addWidget(&_sample_count); addWidget(new QLabel(tr(" @ "))); addWidget(&_sample_rate); - addWidget(&_run_stop_button); - addWidget(&_instant_button); + _run_stop_action = addWidget(&_run_stop_button); + _instant_action = addWidget(&_instant_button); } void SamplingBar::set_device_list( @@ -785,5 +785,29 @@ void SamplingBar::show_session_error( msg.exec(); } +void SamplingBar::reload() +{ + if (_session.get_device()->dev_inst()->mode == LOGIC) { + _icon_instant = QIcon(":/icons/instant.png"); + _icon_instant_dis = QIcon(":/icons/instant_dis.png"); + _instant_button.setIcon(_icon_instant); + _run_stop_action->setVisible(true); + _instant_action->setVisible(true); + enable_toggle(true); + } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + _run_stop_action->setVisible(true); + _instant_action->setVisible(false); + enable_toggle(true); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _icon_instant = QIcon(":/icons/single.png"); + _icon_instant_dis = QIcon(":/icons/single_dis.png"); + _instant_button.setIcon(_icon_instant); + _run_stop_action->setVisible(true); + _instant_action->setVisible(true); + enable_toggle(false); + } + update(); +} + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 4055a1af..ad48c179 100644 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -120,6 +120,7 @@ private slots: public slots: void on_configure(); void zero_adj(); + void reload(); private: SigSession &_session; @@ -145,6 +146,8 @@ private: QIcon _icon_instant_dis; QToolButton _run_stop_button; QToolButton _instant_button; + QAction* _run_stop_action; + QAction* _instant_action; bool _instant; }; diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index 143f9a30..bbd580a2 100644 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -22,19 +22,27 @@ #include "trigbar.h" +#include "../sigsession.h" +#include "../device/devinst.h" +#include "../dialogs/fftoptions.h" + +#include namespace pv { namespace toolbars { -TrigBar::TrigBar(QWidget *parent) : +TrigBar::TrigBar(SigSession &session, QWidget *parent) : QToolBar("Trig Bar", parent), + _session(session), _enable(true), _trig_button(this), _protocol_button(this), _measure_button(this), - _search_button(this) + _search_button(this), + _math_button(this) { setMovable(false); + setContentsMargins(0,0,0,0); connect(&_trig_button, SIGNAL(clicked()), this, SLOT(trigger_clicked())); @@ -60,6 +68,8 @@ TrigBar::TrigBar(QWidget *parent) : _search_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/search-bar_cn.png"))); _search_button.setCheckable(true); + _math_button.setIcon(QIcon::fromTheme("trig", + QIcon(":/icons/math_cn.png"))); #else _trig_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/trigger.png"))); @@ -75,12 +85,29 @@ TrigBar::TrigBar(QWidget *parent) : _search_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/search-bar.png"))); _search_button.setCheckable(true); + _math_button.setIcon(QIcon::fromTheme("trig", + QIcon(":/icons/math.png"))); #endif - addWidget(&_trig_button); - addWidget(&_protocol_button); - addWidget(&_measure_button); - addWidget(&_search_button); + _action_fft = new QAction(this); + _action_fft->setText(QApplication::translate( + "Math", "&FFT", 0)); + _action_fft->setIcon(QIcon::fromTheme("Math", + QIcon(":/icons/fft.png"))); + _action_fft->setObjectName(QString::fromUtf8("actionFft")); + connect(_action_fft, SIGNAL(triggered()), this, SLOT(on_actionFft_triggered())); + + _math_menu = new QMenu(this); + _math_menu->setContentsMargins(0,0,0,0); + _math_menu->addAction(_action_fft); + _math_button.setPopupMode(QToolButton::InstantPopup); + _math_button.setMenu(_math_menu); + + _trig_action = addWidget(&_trig_button); + _protocol_action = addWidget(&_protocol_button); + _measure_action = addWidget(&_measure_button); + _search_action = addWidget(&_search_button); + _math_action = addWidget(&_math_button); } void TrigBar::protocol_clicked() @@ -109,6 +136,7 @@ void TrigBar::enable_toggle(bool enable) _protocol_button.setDisabled(!enable); _measure_button.setDisabled(!enable); _search_button.setDisabled(!enable); + _math_button.setDisabled(!enable); #ifdef LANGUAGE_ZH_CN _trig_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/trigger_cn.png")) : @@ -119,6 +147,8 @@ void TrigBar::enable_toggle(bool enable) QIcon::fromTheme("trig", QIcon(":/icons/measure_dis_cn.png"))); _search_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/search-bar_cn.png")) : QIcon::fromTheme("trig", QIcon(":/icons/search-bar_dis_cn.png"))); + _math_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/math_cn.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/math_dis_cn.png"))); #else _trig_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/trigger.png")) : QIcon::fromTheme("trig", QIcon(":/icons/trigger_dis.png"))); @@ -128,6 +158,9 @@ void TrigBar::enable_toggle(bool enable) QIcon::fromTheme("trig", QIcon(":/icons/measure_dis.png"))); _search_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/search-bar.png")) : QIcon::fromTheme("trig", QIcon(":/icons/search-bar_dis.png"))); + _math_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/math.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/math_dis.png"))); + #endif } @@ -163,5 +196,36 @@ void TrigBar::close_all() } } +void TrigBar::reload() +{ + close_all(); + if (_session.get_device()->dev_inst()->mode == LOGIC) { + _trig_action->setVisible(true); + _protocol_action->setVisible(true); + _measure_action->setVisible(true); + _search_action->setVisible(true); + _math_action->setVisible(false); + } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + _trig_action->setVisible(false); + _protocol_action->setVisible(false); + _measure_action->setVisible(true); + _search_action->setVisible(false); + _math_action->setVisible(false); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _trig_action->setVisible(true); + _protocol_action->setVisible(false); + _measure_action->setVisible(true); + _search_action->setVisible(false); + _math_action->setVisible(true); + } + update(); +} + +void TrigBar::on_actionFft_triggered() +{ + pv::dialogs::FftOptions fft_dlg(this, _session); + fft_dlg.exec(); +} + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index 81e72ef2..7100799e 100644 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -26,19 +26,25 @@ #include #include +#include +#include namespace pv { + +class SigSession; + namespace toolbars { class TrigBar : public QToolBar { Q_OBJECT public: - explicit TrigBar(QWidget *parent = 0); + explicit TrigBar(SigSession &session, QWidget *parent = 0); void enable_toggle(bool enable); void enable_protocol(bool enable); void close_all(); + void reload(); signals: void on_protocol(bool visible); @@ -52,12 +58,24 @@ public slots: void measure_clicked(); void search_clicked(); + void on_actionFft_triggered(); + private: + SigSession& _session; bool _enable; QToolButton _trig_button; QToolButton _protocol_button; QToolButton _measure_button; QToolButton _search_button; + QToolButton _math_button; + QAction* _trig_action; + QAction* _protocol_action; + QAction* _measure_action; + QAction* _search_action; + QAction* _math_action; + + QMenu* _math_menu; + QAction* _action_fft; }; diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 595dff32..de501262 100644 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -54,7 +54,7 @@ const float AnalogSignal::EnvelopeThreshold = 256.0f; AnalogSignal::AnalogSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, const sr_channel * const probe) : - Signal(dev_inst, probe, SR_CHANNEL_ANALOG), + Signal(dev_inst, probe), _data(data) { _colour = SignalColours[probe->index % countof(SignalColours)]; diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index bd076af5..b7117769 100644 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -836,7 +836,7 @@ void DecodeTrace::on_new_decode_data() void DecodeTrace::on_decode_done() { if (_view) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->signals_changed(); } _session.decode_done(); diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index de5e0bbf..558ce007 100644 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -24,6 +24,7 @@ #include +#include "../../extdef.h" #include "dsosignal.h" #include "pv/data/dso.h" #include "pv/data/dsosnapshot.h" @@ -106,13 +107,13 @@ const float DsoSignal::EnvelopeThreshold = 256.0f; const double DsoSignal::TrigMargin = 0.02; const int DsoSignal::UpMargin = 30; -const int DsoSignal::DownMargin = 30; +const int DsoSignal::DownMargin = 0; const int DsoSignal::RightMargin = 30; DsoSignal::DsoSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, const sr_channel * const probe): - Signal(dev_inst, probe, SR_CHANNEL_DSO), + Signal(dev_inst, probe), _data(data), _scale(0), _vDialActive(false), @@ -167,9 +168,14 @@ boost::shared_ptr DsoSignal::data() const return _data; } -void DsoSignal::set_view(pv::view::View *view) +boost::shared_ptr DsoSignal::dso_data() const { - Trace::set_view(view); + return _data; +} + +void DsoSignal::set_viewport(pv::view::Viewport *viewport) +{ + Trace::set_viewport(viewport); update_zeroPos(); const double ms_left = get_view_rect().right() - (MS_RectWidth + MS_RectMargin) * (get_index() + 1); @@ -257,7 +263,7 @@ bool DsoSignal::go_vDialPre() if (_view->session().get_capture_state() == SigSession::Stopped) _scale *= pre_vdiv/_vDial->get_value(); update_zeroPos(); - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); return true; } else { @@ -276,7 +282,7 @@ bool DsoSignal::go_vDialNext() if (_view->session().get_capture_state() == SigSession::Stopped) _scale *= pre_vdiv/_vDial->get_value(); update_zeroPos(); - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); return true; } else { @@ -507,7 +513,7 @@ bool DsoSignal::load_settings() _zero_off = _zeroPos * 255; if (_view) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); } return true; @@ -608,6 +614,11 @@ double DsoSignal::get_zeroRate() return _zeroPos; } +double DsoSignal::get_zeroValue() +{ + return _zero_off; +} + void DsoSignal::set_zeroPos(int pos) { if (enabled()) { @@ -644,7 +655,7 @@ void DsoSignal::set_factor(uint64_t factor) _dev_inst->set_config(_probe, NULL, SR_CONF_FACTOR, g_variant_new_uint64(factor)); _vDial->set_factor(factor); - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); } } @@ -668,7 +679,7 @@ uint64_t DsoSignal::get_factor() void DsoSignal::set_ms_show(bool show) { _ms_show = show; - _view->set_need_update(true); + _view->set_update(_viewport, true); } bool DsoSignal::get_ms_show() const @@ -731,10 +742,10 @@ void DsoSignal::update_zeroPos() QRectF DsoSignal::get_view_rect() const { - assert(_view); + assert(_viewport); return QRectF(0, UpMargin, - _view->viewport()->width() - RightMargin, - _view->viewport()->height() - UpMargin - DownMargin); + _viewport->width() - RightMargin, + _viewport->height() - UpMargin - DownMargin); } void DsoSignal::paint_back(QPainter &p, int left, int right) @@ -745,7 +756,9 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) const int height = get_view_rect().height(); const int width = right - left; - p.setPen(Qt::NoPen); + QPen solidPen(Signal::dsFore); + solidPen.setStyle(Qt::SolidLine); + p.setPen(solidPen); p.setBrush(Trace::dsBack); p.drawRect(left, UpMargin, width, height); @@ -772,13 +785,14 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) p.setBrush(Trace::dsBlue); p.drawRect(shown_offset, UpMargin/2 - 3, shown_len, 6); - QPen pen(Signal::dsFore); - pen.setStyle(Qt::DotLine); - p.setPen(pen); + QPen dashPen(Signal::dsFore); + dashPen.setStyle(Qt::DashLine); + p.setPen(dashPen); const double spanY =height * 1.0 / DS_CONF_DSO_VDIVS; for (i = 1; i <= DS_CONF_DSO_VDIVS; i++) { const double posY = spanY * i + UpMargin; - p.drawLine(left, posY, right, posY); + if (i != DS_CONF_DSO_VDIVS) + p.drawLine(left, posY, right, posY); const double miniSpanY = spanY / 5; for (j = 1; j < 5; j++) { p.drawLine(width / 2.0f - 5, posY - miniSpanY * j, @@ -788,8 +802,8 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) const double spanX = width * 1.0 / DS_CONF_DSO_HDIVS; for (i = 1; i <= DS_CONF_DSO_HDIVS; i++) { const double posX = spanX * i; - p.drawLine(posX, UpMargin, - posX, height + UpMargin); + if (i != DS_CONF_DSO_HDIVS) + p.drawLine(posX, UpMargin,posX, height + UpMargin); const double miniSpanX = spanX / 5; for (j = 1; j < 5; j++) { p.drawLine(posX - miniSpanX * j, height / 2.0f + UpMargin - 5, @@ -954,7 +968,7 @@ void DsoSignal::paint_trace(QPainter &p, } p.drawPolyline(points, point - points); - p.eraseRect(get_view_rect().right(), get_view_rect().top(), + p.eraseRect(get_view_rect().right()+1, get_view_rect().top(), _view->viewport()->width() - get_view_rect().width(), get_view_rect().height()); //delete[] samples; @@ -1095,7 +1109,7 @@ bool DsoSignal::mouse_press(int right, const QPoint pt) { int y = get_y(); bool setted = false; - const vector< boost::shared_ptr > traces(_view->get_traces()); + const vector< boost::shared_ptr > traces(_view->get_traces(ALL_VIEW)); const QRectF vDec_rect = get_rect(DSO_VDEC, y, right); const QRectF vInc_rect = get_rect(DSO_VINC, y, right); const QRectF hDec_rect = get_rect(DSO_HDEC, y, right); @@ -1156,7 +1170,7 @@ bool DsoSignal::mouse_wheel(int right, const QPoint pt, const int shift) { int y = get_y(); const vector< boost::shared_ptr > traces( - _view->get_traces()); + _view->get_traces(ALL_VIEW)); bool setted = false; const QRectF vDial_rect = get_rect(DSO_VDIAL, y, right); const QRectF hDial_rect = get_rect(DSO_HDIAL, y, right); @@ -1363,7 +1377,7 @@ void DsoSignal::paint_measure(QPainter &p) bool setted = false; if (_autoH) { - const vector< boost::shared_ptr > traces(_view->get_traces()); + const vector< boost::shared_ptr > traces(_view->get_traces(ALL_VIEW)); const double upPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.8; const double dnPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.2; if (_period > upPeriod) { @@ -1404,18 +1418,18 @@ bool DsoSignal::measure(const QPointF &p) { if (_ms_gear_rect.contains(QPoint(p.x(), p.y()))) { _ms_gear_hover = true; - _view->set_need_update(true); + _view->set_update(_viewport, true); return false; } else if (_ms_gear_hover) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _ms_gear_hover = false; } if (_ms_show_rect.contains(QPoint(p.x(), p.y()))) { _ms_show_hover = true; - _view->set_need_update(true); + _view->set_update(_viewport, true); return false; } else if (_ms_show_hover){ - _view->set_need_update(true); + _view->set_update(_viewport, true); _ms_show_hover = false; } diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index a2669d8a..032287e6 100644 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -105,7 +105,8 @@ public: virtual ~DsoSignal(); boost::shared_ptr data() const; - void set_view(pv::view::View *view); + boost::shared_ptr dso_data() const; + void set_viewport(pv::view::Viewport *viewport); void set_scale(float scale); float get_scale(); @@ -154,6 +155,7 @@ public: */ int get_zeroPos(); double get_zeroRate(); + double get_zeroValue(); /** * Sets the mid-Y position of this signal. */ diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index ca38299f..7ccb9828 100644 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -24,6 +24,7 @@ #include "header.h" #include "view.h" +#include "../../extdef.h" #include "trace.h" #include "dsosignal.h" #include "logicsignal.h" @@ -95,7 +96,7 @@ boost::shared_ptr Header::get_mTrace( { const int w = width(); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); BOOST_FOREACH(const boost::shared_ptr t, traces) { @@ -120,7 +121,7 @@ void Header::paintEvent(QPaintEvent*) const int w = width(); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); const bool dragging = !_drag_traces.empty(); BOOST_FOREACH(const boost::shared_ptr t, traces) @@ -137,7 +138,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event) assert(event); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); if (event->button() & Qt::LeftButton) { _mouse_down_point = event->pos(); @@ -161,7 +162,7 @@ void Header::mousePressEvent(QMouseEvent *event) assert(event); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); int action; const bool instant = _view.session().get_instant(); if (instant && _view.session().get_capture_state() == SigSession::Running) @@ -229,7 +230,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) if (action == Trace::COLOR && _colorFlag) { _context_trace = mTrace; changeColor(event); - _view.set_need_update(true); + _view.set_all_update(true); } else if (action == Trace::NAME && _nameFlag) { _context_trace = mTrace; changeName(event); @@ -238,7 +239,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) if (_moveFlag) { //move(event); _view.signals_changed(); - _view.set_need_update(true); + _view.set_all_update(true); } _colorFlag = false; _nameFlag = false; @@ -253,7 +254,7 @@ void Header::wheelEvent(QWheelEvent *event) if (event->orientation() == Qt::Vertical) { const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); // Vertical scrolling double shift = event->delta() / 20.0; BOOST_FOREACH(const boost::shared_ptr t, traces) diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index 00df932b..94e96d7b 100644 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -52,7 +52,7 @@ const int LogicSignal::StateRound = 5; LogicSignal::LogicSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, const sr_channel * const probe) : - Signal(dev_inst, probe, SR_CHANNEL_LOGIC), + Signal(dev_inst, probe), _data(data), _trig(NONTRIG) { diff --git a/DSView/pv/view/mathtrace.cpp b/DSView/pv/view/mathtrace.cpp index 7aca389c..d8bb16c2 100644 --- a/DSView/pv/view/mathtrace.cpp +++ b/DSView/pv/view/mathtrace.cpp @@ -1,7 +1,488 @@ -#include "ffttrace.h" +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "mathtrace.h" -FftTrace::FftTrace() +#include +#include + +#include +#include + +#include "../sigsession.h" +#include "../data/dso.h" +#include "../data/dsosnapshot.h" +#include "../view/dsosignal.h" +#include "../view/viewport.h" +#include "../device/devinst.h" + +#include "../data/mathstack.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace view { + +const int MathTrace::UpMargin = 0; +const int MathTrace::DownMargin = 0; +const int MathTrace::RightMargin = 30; +const QString MathTrace::FFT_ViewMode[2] = { + "Linear RMS", + "DBV RMS" +}; + +const QString MathTrace::FreqPrefixes[9] = + {"", "", "", "", "K", "M", "G", "T", "P"}; +const int MathTrace::FirstSIPrefixPower = -9; +const int MathTrace::LastSIPrefixPower = 15; +const int MathTrace::Pricision = 2; +const int MathTrace::FreqMinorDivNum = 10; +const int MathTrace::TickHeight = 15; +const int MathTrace::VolDivNum = 5; + +const int MathTrace::DbvRanges[4] = { + 100, + 120, + 150, + 200, +}; + +const int MathTrace::HoverPointSize = 3; +const double MathTrace::VerticalRate = 1.0 / 2000.0; + +MathTrace::MathTrace(pv::SigSession &session, + boost::shared_ptr math_stack, int index) : + Trace("FFT("+QString::number(index)+")", index, SR_CHANNEL_FFT), + _session(session), + _math_stack(math_stack), + _enable(false), + _view_mode(0), + _hover_en(false), + _scale(1), + _offset(0) +{ + const vector< boost::shared_ptr > sigs(_session.get_signals()); + for(size_t i = 0; i < sigs.size(); i++) { + const boost::shared_ptr s(sigs[i]); + assert(s); + if (dynamic_pointer_cast(s) && index == s->get_index()) + _colour = s->get_colour(); + } +} + +MathTrace::~MathTrace() { } +bool MathTrace::enabled() const +{ + return _enable; +} + +void MathTrace::set_enable(bool enable) +{ + _enable = enable; +} + +int MathTrace::view_mode() const +{ + return _view_mode; +} + +void MathTrace::set_view_mode(int mode) +{ + assert(mode < sizeof(FFT_ViewMode)/sizeof(FFT_ViewMode[0])); + _view_mode = mode; +} + +std::vector MathTrace::get_view_modes_support() +{ + std::vector modes; + for (int i = 0; i < sizeof(FFT_ViewMode)/sizeof(FFT_ViewMode[0]); i++) { + modes.push_back(FFT_ViewMode[i]); + } + return modes; +} + +const boost::shared_ptr& MathTrace::get_math_stack() const +{ + return _math_stack; +} + +void MathTrace::init_zoom() +{ + _scale = 1; + _offset = 0; +} + +void MathTrace::zoom(double steps, int offset) +{ + if (!_view) + return; + + const int width = get_view_rect().width(); + double pre_offset = _offset + _scale*offset/width; + _scale *= std::pow(3.0/2.0, -steps); + _scale = max(min(_scale, 1.0), 100.0/_math_stack->get_sample_num()); + _offset = pre_offset - _scale*offset/width; + _offset = max(min(_offset, 1-_scale), 0.0); + + _view->set_update(_viewport, true); + _view->update(); +} + +void MathTrace::set_offset(double delta) +{ + int width = get_view_rect().width(); + _offset = _offset + (delta*_scale / width); + _offset = max(min(_offset, 1-_scale), 0.0); + + _view->set_update(_viewport, true); + _view->update(); +} + +double MathTrace::get_offset() const +{ + return _offset; +} + +void MathTrace::set_scale(double scale) +{ + _scale = max(min(scale, 1.0), 100.0/_math_stack->get_sample_num()); + + _view->set_update(_viewport, true); + _view->update(); +} + +double MathTrace::get_scale() const +{ + return _scale; +} + +void MathTrace::set_dbv_range(int range) +{ + _dbv_range = range; +} + +int MathTrace::dbv_range() const +{ + return _dbv_range; +} + +std::vector MathTrace::get_dbv_ranges() +{ + std::vector range; + for (int i = 0; i < sizeof(DbvRanges)/sizeof(DbvRanges[0]); i++) { + range.push_back(DbvRanges[i]); + } + return range; +} + +QString MathTrace::format_freq(double freq, unsigned precision) +{ + if (freq <= 0) { + return "0Hz"; + } else { + const int order = floor(log10f(freq)); + assert(order >= FirstSIPrefixPower); + assert(order <= LastSIPrefixPower); + const int prefix = floor((order - FirstSIPrefixPower)/ 3.0f); + const double divider = pow(10.0, max(prefix * 3.0 + FirstSIPrefixPower, 0.0)); + + QString s; + QTextStream ts(&s); + ts.setRealNumberPrecision(precision); + ts << fixed << freq / divider << + FreqPrefixes[prefix] << "Hz"; + return s; + } +} + +bool MathTrace::measure(const QPointF &p) +{ + _hover_en = false; + if(!_view || !enabled()) + return false; + + const QRectF window = get_view_rect(); + if (!window.contains(p)) + return false; + + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return false; + + const int full_size = (_math_stack->get_sample_num()/2+1); + const double view_off = full_size * _offset; + const int view_size = full_size*_scale; + const double sample_per_pixels = view_size/window.width(); + _hover_index = std::round(p.x() * sample_per_pixels + view_off); + + if (_hover_index < full_size) + _hover_en = true; + + //_view->set_update(_viewport, true); + _view->update(); + return true; +} + + +void MathTrace::paint_back(QPainter &p, int left, int right) +{ + if(!_view) + return; + + int i, j; + const int height = get_view_rect().height(); + const int width = right - left; + + QPen solidPen(Signal::dsFore); + solidPen.setStyle(Qt::SolidLine); + p.setPen(solidPen); + p.setBrush(Trace::dsBack); + p.drawRect(left, UpMargin, width, height); +} + +void MathTrace::paint_mid(QPainter &p, int left, int right) +{ + if(!_view) + return; + assert(right >= left); + + if (enabled()) { + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return; + + QColor trace_colour = _colour; + trace_colour.setAlpha(150); + p.setPen(trace_colour); + + const int full_size = (_math_stack->get_sample_num()/2+1); + const double view_off = full_size * _offset; + const int view_start = floor(view_off); + const int view_size = full_size*_scale; + QPointF *points = new QPointF[samples.size()]; + QPointF *point = points; + + const bool dc_ignored = _math_stack->dc_ignored(); + const double height = get_view_rect().height(); + const double width = right - left; + const double pixels_per_sample = width/view_size; + + double vdiv; + double vfactor; + double voffset; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if(dsoSig->get_index() == _math_stack->get_index()) { + vdiv = dsoSig->get_vDialValue(); + vfactor = dsoSig->get_factor(); + voffset = dsoSig->get_zeroRate(); + break; + } + } + } + if (_view_mode == 0) { + _vmin = 0; + _vmax = (vdiv*DS_CONF_DSO_HDIVS*vfactor)*VerticalRate; + } else { + _vmax = 20*log10((vdiv*DS_CONF_DSO_HDIVS*vfactor)*VerticalRate); + _vmin = _vmax - _dbv_range; + } + + //const double max_value = *std::max_element(dc_ignored ? ++samples.begin() : samples.begin(), samples.end()); + //const double min_value = *std::min_element(dc_ignored ? ++samples.begin() : samples.begin(), samples.end()); + //_vmax = (_view_mode == 0) ? max_value : 20*log10(max_value); + //_vmin = (_view_mode == 0) ? min_value : 20*log10(min_value); + const double scale = height / (_vmax - _vmin); + + double x = (view_start-view_off)*pixels_per_sample; + uint64_t sample = view_start; + if (dc_ignored && sample == 0) { + sample++; + x += pixels_per_sample; + } + double min_mag = pow(10.0, _vmin/20); + do{ + double mag = samples[sample]; + if (_view_mode != 0) { + if (mag < min_mag) + mag = _vmin; + else + mag = 20*log10(mag); + } + const double y = height - (scale * (mag - _vmin)); + *point++ = QPointF(x, y); + x += pixels_per_sample; + sample++; + }while(x= left); + + const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, "8").height(); + const double width = get_view_rect().width(); + const double height = get_view_rect().height(); + double blank_top = 0; + double blank_right = width; + + // horizontal ruler + const double NyFreq = _session.get_device()->get_sample_rate() / (2.0 * _math_stack->get_sample_interval()); + const double deltaFreq = _session.get_device()->get_sample_rate() * 1.0 / + (_math_stack->get_sample_num() * _math_stack->get_sample_interval()); + const double FreqRange = NyFreq * _scale; + const double FreqOffset = NyFreq * _offset; + + const int order = (int)floor(log10(FreqRange)); + const double multiplier = (pow(10.0, order) == FreqRange) ? FreqRange/10 : pow(10.0, order); + const double freq_per_pixel = FreqRange / width; + + p.setPen(Trace::DARK_FORE); + p.setBrush(Qt::NoBrush); + double tick_freq = multiplier * (int)floor(FreqOffset / multiplier); + int division = (int)round(tick_freq * FreqMinorDivNum / multiplier); + double x = (tick_freq - FreqOffset) / freq_per_pixel; + do{ + if (division%FreqMinorDivNum == 0) { + QString freq_str = format_freq(tick_freq); + double typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, freq_str).width() + 10; + p.drawLine(x, 1, x, TickHeight); + if (x > typical_width/2 && (width-x) > typical_width/2) + p.drawText(x-typical_width/2, TickHeight, typical_width, text_height, + AlignCenter | AlignTop | TextDontClip, freq_str); + } else { + p.drawLine(x, 1, x, TickHeight/2); + } + tick_freq += multiplier/FreqMinorDivNum; + division++; + x = (tick_freq - FreqOffset) / freq_per_pixel; + } while(x < width); + blank_top = max(blank_top, (double)TickHeight + text_height); + + // delta Frequency + QString freq_str = QString::fromWCharArray(L" \u0394") + "Freq: " + format_freq(deltaFreq,4); + p.drawText(0, 0, width, get_view_rect().height(), + AlignRight | AlignBottom | TextDontClip, freq_str); + double delta_left = width-p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, freq_str).width(); + blank_right = min(delta_left, blank_right); + + // Vertical ruler + const double vRange = _vmax - _vmin; + const double vOffset = _vmin; + const double vol_per_tick = vRange / VolDivNum; + + p.setPen(Trace::DARK_FORE); + p.setBrush(Qt::NoBrush); + double tick_vol = vol_per_tick + vOffset; + double y = height - height / VolDivNum; + const QString unit = (_view_mode == 0) ? "" : "dbv"; + do{ + if (y > text_height && y < (height - text_height)) { + QString vol_str = QString::number(tick_vol, 'f', Pricision) + unit; + double vol_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, vol_str).width(); + p.drawLine(width, y, width-TickHeight/2, y); + p.drawText(width-TickHeight-vol_width, y-text_height/2, vol_width, text_height, + AlignCenter | AlignTop | TextDontClip, vol_str); + blank_right = min(width-TickHeight-vol_width, blank_right); + } + tick_vol += vol_per_tick; + y -= height / VolDivNum; + } while(y > 0); + + // Hover measure + if (_hover_en) { + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return; + const int full_size = (_math_stack->get_sample_num()/2+1); + const double view_off = full_size * _offset; + const int view_size = full_size*_scale; + const double scale = height / (_vmax - _vmin); + const double pixels_per_sample = width/view_size; + double x = (_hover_index-view_off)*pixels_per_sample; + double min_mag = pow(10.0, _vmin/20); + _hover_value = samples[_hover_index]; + if (_view_mode != 0) { + if (_hover_value < min_mag) + _hover_value = _vmin; + else + _hover_value = 20*log10(_hover_value); + } + const double y = height - (scale * (_hover_value - _vmin)); + _hover_point = QPointF(x, y); + + p.setPen(QPen(Trace::DARK_FORE, 1, Qt::DashLine)); + p.setBrush(Qt::NoBrush); + p.drawLine(_hover_point.x(), 0, _hover_point.x(), height); + + QString hover_str = QString::number(_hover_value, 'f', 4) + unit + "@" + format_freq(deltaFreq * _hover_index, 4); + const int hover_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, hover_str).width(); + const int hover_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, hover_str).height(); + QRectF hover_rect(_hover_point.x(), _hover_point.y()-hover_height, hover_width, hover_height); + if (hover_rect.right() > blank_right) + hover_rect.moveRight(min(_hover_point.x(), blank_right)); + if (hover_rect.top() < blank_top) + hover_rect.moveTop(max(_hover_point.y(), blank_top)); + if (hover_rect.top() > 0) + p.drawText(hover_rect, AlignCenter | AlignTop | TextDontClip, hover_str); + + p.setPen(Qt::NoPen); + p.setBrush(Trace::DARK_FORE); + p.drawEllipse(_hover_point, HoverPointSize, HoverPointSize); + } +} + +void MathTrace::paint_type_options(QPainter &p, int right, const QPoint pt) +{ + (void)p; + (void)pt; + (void)right; +} + +QRectF MathTrace::get_view_rect() const +{ + assert(_viewport); + return QRectF(0, UpMargin, + _viewport->width() - RightMargin, + _viewport->height() - UpMargin - DownMargin); +} + +} // namespace view +} // namespace pv diff --git a/DSView/pv/view/mathtrace.h b/DSView/pv/view/mathtrace.h index a64ede6a..7a39babb 100644 --- a/DSView/pv/view/mathtrace.h +++ b/DSView/pv/view/mathtrace.h @@ -1,11 +1,156 @@ -#ifndef FFTTRACE_H -#define FFTTRACE_H +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef DSVIEW_PV_VIEW_MATHTRACE_H +#define DSVIEW_PV_VIEW_MATHTRACE_H -class FftTrace +#include "trace.h" + +#include +#include + +#include + +struct srd_channel; + +namespace pv { + +class SigSession; + +namespace data{ +class MathStack; +} + +namespace view { + +class MathTrace : public Trace { + Q_OBJECT + +private: + static const int UpMargin; + static const int DownMargin; + static const int RightMargin; + static const QString FFT_ViewMode[2]; + + static const QString FreqPrefixes[9]; + static const int FirstSIPrefixPower; + static const int LastSIPrefixPower; + static const int Pricision; + static const int FreqMinorDivNum; + static const int TickHeight; + static const int VolDivNum; + + static const int DbvRanges[4]; + + static const int HoverPointSize; + + static const double VerticalRate; + public: - FftTrace(); + MathTrace(pv::SigSession &session, + boost::shared_ptr math_stack, int index); + ~MathTrace(); + + bool enabled() const; + void set_enable(bool enable); + + void init_zoom(); + void zoom(double steps, int offset); + bool zoom_hit() const; + void set_zoom_hit(bool hit); + + void set_offset(double delta); + double get_offset() const; + + void set_scale(double scale); + double get_scale() const; + + void set_dbv_range(int range); + int dbv_range() const; + std::vector get_dbv_ranges(); + + int view_mode() const; + void set_view_mode(int mode); + std::vector get_view_modes_support(); + + const boost::shared_ptr& get_math_stack() const; + + static QString format_freq(double freq, unsigned precision = Pricision); + + bool measure(const QPointF &p); + + /** + * Paints the background layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal. + * @param right the x-coordinate of the right edge of the signal. + **/ + void paint_back(QPainter &p, int left, int right); + + /** + * Paints the mid-layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + void paint_mid(QPainter &p, int left, int right); + + /** + * Paints the foreground layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + void paint_fore(QPainter &p, int left, int right); + + QRectF get_view_rect() const; + +protected: + void paint_type_options(QPainter &p, int right, const QPoint pt); + +private: + +private slots: + +private: + pv::SigSession &_session; + boost::shared_ptr _math_stack; + + bool _enable; + int _view_mode; + + double _vmax; + double _vmin; + int _dbv_range; + + uint64_t _hover_index; + bool _hover_en; + QPointF _hover_point; + double _hover_value; + + double _scale; + double _offset; }; -#endif // FFTTRACE_H +} // namespace view +} // namespace pv + +#endif // DSVIEW_PV_VIEW_FFTTRACE_H diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 3fdab4b9..1bbfb340 100644 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -109,7 +109,7 @@ QString Ruler::format_freq(double period, unsigned precision) QString s; QTextStream ts(&s); ts.setRealNumberPrecision(precision); - ts << fixed << forcesign << 1 / (period * multiplier) << + ts << fixed << 1 / (period * multiplier) << FreqPrefixes[prefix] << "Hz"; return s; } diff --git a/DSView/pv/view/signal.cpp b/DSView/pv/view/signal.cpp index e4cba490..04a4e6ed 100644 --- a/DSView/pv/view/signal.cpp +++ b/DSView/pv/view/signal.cpp @@ -35,8 +35,8 @@ namespace pv { namespace view { Signal::Signal(boost::shared_ptr dev_inst, - const sr_channel *const probe, int type) : - Trace(probe->name, probe->index, type), + const sr_channel *const probe) : + Trace(probe->name, probe->index, probe->type), _dev_inst(dev_inst), _probe(probe) { diff --git a/DSView/pv/view/signal.h b/DSView/pv/view/signal.h index 3ad90f44..632f1e37 100644 --- a/DSView/pv/view/signal.h +++ b/DSView/pv/view/signal.h @@ -57,7 +57,7 @@ private: protected: Signal(boost::shared_ptr dev_inst, - const sr_channel * const probe, int type); + const sr_channel * const probe); /** * Copy constructor diff --git a/DSView/pv/view/trace.cpp b/DSView/pv/view/trace.cpp index 3c79bc1a..661f59f5 100644 --- a/DSView/pv/view/trace.cpp +++ b/DSView/pv/view/trace.cpp @@ -43,7 +43,7 @@ const QColor Trace::dsRed = QColor(213, 15, 37, 255); const QColor Trace::dsGreen = QColor(0, 153, 37, 200); const QColor Trace::dsGray = QColor(0x88, 0x8A, 0x85, 60); const QColor Trace::dsFore = QColor(0xff, 0xff, 0xff, 60); -const QColor Trace::dsBack = QColor(0x16, 0x18, 0x23, 180); +const QColor Trace::dsBack = QColor(0x16, 0x18, 0x23, 200); const QColor Trace::dsDisable = QColor(0x88, 0x8A, 0x85, 200); const QColor Trace::dsActive = QColor(17, 133, 209, 255); const QColor Trace::dsLightBlue = QColor(17, 133, 209, 150); @@ -53,6 +53,7 @@ const QPen Trace::SignalAxisPen = QColor(128, 128, 128, 64); const QColor Trace::DARK_BACK = QColor(48, 47, 47, 255); const QColor Trace::DARK_FORE = QColor(150, 150, 150, 255); const QColor Trace::DARK_HIGHLIGHT = QColor(32, 32, 32, 255); +const QColor Trace::DARK_BLUE = QColor(17, 133, 209, 255); const QColor Trace::PROBE_COLORS[8] = { QColor(0x50, 0x50, 0x50), // Black @@ -187,7 +188,7 @@ void Trace::set_old_v_offset(int v_offset) int Trace::get_zeroPos() { - return _v_offset - _view->v_offset(); + return _v_offset; } int Trace::get_totalHeight() const @@ -211,6 +212,17 @@ pv::view::View* Trace::get_view() const return _view; } +void Trace::set_viewport(pv::view::Viewport *viewport) +{ + assert(viewport); + _viewport = viewport; +} + +pv::view::Viewport* Trace::get_viewport() const +{ + return _viewport; +} + void Trace::paint_back(QPainter &p, int left, int right) { QPen pen(Signal::dsGray); @@ -236,6 +248,9 @@ void Trace::paint_fore(QPainter &p, int left, int right) void Trace::paint_label(QPainter &p, int right, const QPoint pt) { + if (_type == SR_CHANNEL_FFT && !enabled()) + return; + compute_text_size(p); const int y = get_y(); @@ -267,7 +282,7 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) }; p.setPen(Qt::transparent); - if (_type == SR_CHANNEL_DSO) { + if (_type == SR_CHANNEL_DSO || _type == SR_CHANNEL_FFT) { p.setBrush((label_rect.contains(pt) || selected()) ? _colour.darker() : _colour); p.drawPolygon(points, countof(points)); } else { @@ -284,6 +299,8 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "A"); else if (_type == SR_CHANNEL_DECODER) p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "D"); + else if (_type == SR_CHANNEL_FFT) + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "M"); else p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(_index_list.front())); } @@ -355,7 +372,7 @@ QRectF Trace::get_view_rect() const int Trace::get_y() const { - return _v_offset - _view->v_offset(); + return _v_offset; } QColor Trace::get_text_colour() const diff --git a/DSView/pv/view/trace.h b/DSView/pv/view/trace.h index 26d9b504..1c30de77 100644 --- a/DSView/pv/view/trace.h +++ b/DSView/pv/view/trace.h @@ -31,6 +31,8 @@ #include +#include + #include "selectableitem.h" #include "dsldial.h" @@ -40,6 +42,7 @@ namespace pv { namespace view { class View; +class Viewport; class Trace : public SelectableItem { @@ -73,6 +76,7 @@ public: static const QColor DARK_BACK; static const QColor DARK_FORE; static const QColor DARK_HIGHLIGHT; + static const QColor DARK_BLUE; static const QColor PROBE_COLORS[8]; @@ -166,6 +170,8 @@ public: virtual void set_view(pv::view::View *view); pv::view::View* get_view() const; + virtual void set_viewport(pv::view::Viewport *viewport); + pv::view::Viewport* get_viewport() const; /** * Paints the background layer of the trace with a QPainter @@ -290,6 +296,7 @@ signals: protected: pv::view::View *_view; + pv::view::Viewport *_viewport; QString _name; QColor _colour; diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index df0e2e87..43cf5868 100644 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -41,6 +41,7 @@ #include "dsosignal.h" #include "view.h" #include "viewport.h" +#include "mathtrace.h" #include "../device/devinst.h" #include "pv/sigsession.h" @@ -68,25 +69,19 @@ const QColor View::CursorAreaColour(220, 231, 243); const QSizeF View::LabelPadding(4, 4); View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent) : - QAbstractScrollArea(parent), + QScrollArea(parent), _session(session), _sampling_bar(sampling_bar), - _viewport(new Viewport(*this)), - _ruler(new Ruler(*this)), - _header(new Header(*this)), - _devmode(new DevMode(this, session)), _scale(1e-8), _preScale(1e-6), _maxscale(1e9), _minscale(1e-15), _offset(0), _preOffset(0), - _v_offset(0), _updating_scroll(false), - _need_update(false), _show_cursors(false), _trig_pos(0), - _hover_point(-1, -1) + _hover_point(-1, -1) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); @@ -95,8 +90,60 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(v_scroll_value_changed(int))); + // trace viewport map + _trace_view_map[SR_CHANNEL_LOGIC] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_GROUP] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_DECODER] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_ANALOG] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_DSO] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_FFT] = FFT_VIEW; + + _active_viewport = NULL; + _ruler = new Ruler(*this); + _header = new Header(*this); + _devmode = new DevMode(this, session); + setViewportMargins(headerWidth(), RulerHeight, 0, 0); - setViewport(_viewport); + //setViewport(_viewport); + + // windows splitter + _time_viewport = new Viewport(*this, TIME_VIEW); + _time_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + _time_viewport->setMinimumHeight(100); + connect(_time_viewport, SIGNAL(measure_updated()), + this, SLOT(on_measure_updated())); + _fft_viewport = new Viewport(*this, FFT_VIEW); + _fft_viewport->setVisible(false); + _fft_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + _fft_viewport->setMinimumHeight(100); + connect(_fft_viewport, SIGNAL(measure_updated()), + this, SLOT(on_measure_updated())); + + _vsplitter = new QSplitter(this); + _vsplitter->setOrientation(Qt::Vertical); + _vsplitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + _viewport_list.push_back(_time_viewport); + _vsplitter->addWidget(_time_viewport); + _vsplitter->setCollapsible(0, false); + _vsplitter->setStretchFactor(0, 2); + _viewport_list.push_back(_fft_viewport); + _vsplitter->addWidget(_fft_viewport); + _vsplitter->setCollapsible(1, false); + _vsplitter->setStretchFactor(1, 1); + + _viewcenter = new QWidget(this); + _viewcenter->setContentsMargins(0,0,0,0); + QGridLayout* layout = new QGridLayout(_viewcenter); + layout->setContentsMargins(0,0,0,0); + _viewcenter->setLayout(layout); + layout->addWidget(_vsplitter, 0, 0); + QWidget* bottom = new QWidget(this); + bottom->setFixedHeight(10); + layout->addWidget(bottom, 1, 0); + setViewport(_viewcenter); + connect(_vsplitter, SIGNAL(splitterMoved(int,int)), + this, SLOT(splitterMoved(int, int))); connect(&_session, SIGNAL(device_setted()), _devmode, SLOT(set_device())); @@ -117,12 +164,13 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget connect(_header, SIGNAL(header_updated()), this, SLOT(header_updated())); - _viewport->installEventFilter(this); + _time_viewport->installEventFilter(this); + _fft_viewport->installEventFilter(this); _ruler->installEventFilter(this); _header->installEventFilter(this); _devmode->installEventFilter(this); - _viewport->setObjectName(tr("ViewArea_viewport")); + _viewcenter->setObjectName(tr("ViewArea_center")); _ruler->setObjectName(tr("ViewArea_ruler")); _header->setObjectName(tr("ViewArea_header")); @@ -148,11 +196,6 @@ double View::offset() const return _offset; } -int View::v_offset() const -{ - return _v_offset; -} - double View::get_minscale() const { return _minscale; @@ -168,14 +211,15 @@ void View::zoom(double steps) zoom(steps, get_view_width() / 2); } -void View::set_need_update(bool need_update) +void View::set_update(Viewport *viewport, bool need_update) { - _need_update = need_update; + viewport->set_need_update(need_update); } -bool View::need_update() const +void View::set_all_update(bool need_update) { - return _need_update; + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->set_need_update(need_update); } void View::update_sample(bool instant) @@ -235,7 +279,7 @@ void View::zoom(double steps, int offset) if (_scale != _preScale || _offset != _preOffset) { _header->update(); _ruler->update(); - _viewport->update(); + viewport_update(); update_scroll(); } //} @@ -255,7 +299,7 @@ void View::set_scale_offset(double scale, double offset) update_scroll(); _header->update(); _ruler->update(); - _viewport->update(); + viewport_update(); } //} } @@ -269,25 +313,57 @@ void View::set_preScale_preOffset() set_scale_offset(_preScale, _preOffset); } -vector< boost::shared_ptr > View::get_traces() const +vector< boost::shared_ptr > View::get_traces(int type) { +// const vector< boost::shared_ptr > sigs(_session.get_signals()); +// const vector< boost::shared_ptr > groups(_session.get_group_signals()); +//#ifdef ENABLE_DECODE +// const vector< boost::shared_ptr > decode_sigs( +// _session.get_decode_signals()); +// vector< boost::shared_ptr > traces( +// sigs.size() + groups.size() + decode_sigs.size()); +//#else +// vector< boost::shared_ptr > traces(sigs.size() + groups.size()); +//#endif + +// vector< boost::shared_ptr >::iterator i = traces.begin(); +// i = copy(sigs.begin(), sigs.end(), i); +//#ifdef ENABLE_DECODE +// i = copy(decode_sigs.begin(), decode_sigs.end(), i); +//#endif +// i = copy(groups.begin(), groups.end(), i); + +// stable_sort(traces.begin(), traces.end(), compare_trace_v_offsets); +// return traces; + const vector< boost::shared_ptr > sigs(_session.get_signals()); const vector< boost::shared_ptr > groups(_session.get_group_signals()); #ifdef ENABLE_DECODE const vector< boost::shared_ptr > decode_sigs( _session.get_decode_signals()); - vector< boost::shared_ptr > traces( - sigs.size() + groups.size() + decode_sigs.size()); -#else - vector< boost::shared_ptr > traces(sigs.size() + groups.size()); #endif + const vector< boost::shared_ptr > maths(_session.get_math_signals()); - vector< boost::shared_ptr >::iterator i = traces.begin(); - i = copy(sigs.begin(), sigs.end(), i); + vector< boost::shared_ptr > traces; + BOOST_FOREACH(boost::shared_ptr t, sigs) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } #ifdef ENABLE_DECODE - i = copy(decode_sigs.begin(), decode_sigs.end(), i); + BOOST_FOREACH(boost::shared_ptr t, decode_sigs) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } #endif - i = copy(groups.begin(), groups.end(), i); + BOOST_FOREACH(boost::shared_ptr t, groups) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } + + BOOST_FOREACH(boost::shared_ptr t, maths) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } stable_sort(traces.begin(), traces.end(), compare_trace_v_offsets); return traces; @@ -323,21 +399,21 @@ void View::show_cursors(bool show) { _show_cursors = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::show_trig_cursor(bool show) { _show_trig_cursor = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::show_search_cursor(bool show) { _show_search_cursor = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::set_trig_pos(quint64 trig_pos) @@ -353,7 +429,7 @@ void View::set_trig_pos(quint64 trig_pos) _trigger_time = _trigger_time.addSecs(secs); _ruler->update(); - _viewport->update(); + viewport_update(); } void View::set_search_pos(uint64_t search_pos) @@ -365,7 +441,7 @@ void View::set_search_pos(uint64_t search_pos) _search_cursor->set_index(search_pos); set_scale_offset(_scale, time - _scale * get_view_width() / 2); _ruler->update(); - _viewport->update(); + viewport_update(); } uint64_t View::get_trig_pos() @@ -385,7 +461,7 @@ const QPointF& View::hover_point() const void View::normalize_layout() { - const vector< boost::shared_ptr > traces(get_traces()); + const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); int v_min = INT_MAX; BOOST_FOREACH(const boost::shared_ptr t, traces) @@ -395,7 +471,7 @@ void View::normalize_layout() BOOST_FOREACH(boost::shared_ptr t, traces) t->set_v_offset(t->get_v_offset() + delta); - verticalScrollBar()->setSliderPosition(_v_offset + delta); + verticalScrollBar()->setSliderPosition(delta); v_scroll_value_changed(verticalScrollBar()->sliderPosition()); } @@ -422,9 +498,9 @@ void View::get_scroll_layout(double &length, double &offset) const void View::update_scroll() { - assert(_viewport); + assert(_viewcenter); - const QSize areaSize = _viewport->size(); + const QSize areaSize = _viewcenter->size(); // Set the horizontal scroll bar double length = 0, offset = 0; @@ -448,8 +524,7 @@ void View::update_scroll() // Set the vertical scrollbar verticalScrollBar()->setPageStep(areaSize.height()); - verticalScrollBar()->setRange(0, - _viewport->get_total_height() - areaSize.height()); + verticalScrollBar()->setRange(0,0); } void View::update_scale() @@ -473,47 +548,93 @@ void View::update_scale() _trig_cursor->set_index(_trig_pos); _ruler->update(); - _viewport->update(); + viewport_update(); } void View::signals_changed() { int total_rows = 0; uint8_t max_height = MaxHeightUnit; - const vector< boost::shared_ptr > traces(get_traces()); - BOOST_FOREACH(const boost::shared_ptr t, traces) - { - assert(t); - if (dynamic_pointer_cast(t) || - t->enabled()) - total_rows += t->rows_size(); + vector< boost::shared_ptr > time_traces; + vector< boost::shared_ptr > fft_traces; + BOOST_FOREACH(const boost::shared_ptr t, get_traces(ALL_VIEW)) { + if (_trace_view_map[t->get_type()] == TIME_VIEW) + time_traces.push_back(t); + else if (_trace_view_map[t->get_type()] == FFT_VIEW) + if (t->enabled()) + fft_traces.push_back(t); } - const double height = (_viewport->height() - - horizontalScrollBar()->height() - - 2 * SignalMargin * traces.size()) * 1.0 / total_rows; - - if (_session.get_device()->dev_inst()->mode == LOGIC) { - GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); - if (gvar != NULL) { - max_height = (g_variant_get_byte(gvar) + 1) * MaxHeightUnit; - g_variant_unref(gvar); + if (!fft_traces.empty()) { + if (!_fft_viewport->isVisible()) { + _fft_viewport->setVisible(true); + _fft_viewport->clear_measure(); + _viewport_list.push_back(_fft_viewport); + _vsplitter->refresh(); + } + BOOST_FOREACH(boost::shared_ptr t, fft_traces) { + t->set_view(this); + t->set_viewport(_fft_viewport); + t->set_totalHeight(_fft_viewport->height()); + t->set_v_offset(_fft_viewport->geometry().bottom()); } - _signalHeight = (int)((height <= 0) ? 1 : (height >= max_height) ? max_height : height); } else { - _signalHeight = (int)((height <= 0) ? 1 : height); - } - _spanY = _signalHeight + 2 * SignalMargin; - int next_v_offset = SignalMargin; - BOOST_FOREACH(boost::shared_ptr t, traces) { - t->set_view(this); - const double traceHeight = _signalHeight*t->rows_size(); - t->set_totalHeight((int)traceHeight); - t->set_v_offset(next_v_offset + 0.5 * traceHeight + SignalMargin); - next_v_offset += traceHeight + 2 * SignalMargin; - } + _fft_viewport->setVisible(false); + _vsplitter->refresh(); + + // Find the decoder in the stack + std::list< Viewport *>::iterator iter = _viewport_list.begin(); + for(int i = 0; i < _viewport_list.size(); i++, iter++) + if ((*iter) == _fft_viewport) + break; + // Delete the element + if (iter != _viewport_list.end()) + _viewport_list.erase(iter); + } + + if (!time_traces.empty() && _time_viewport) { + BOOST_FOREACH(const boost::shared_ptr t, time_traces) { + assert(t); + if (dynamic_pointer_cast(t) || + t->enabled()) + total_rows += t->rows_size(); + } + + const double height = (_time_viewport->height() + - horizontalScrollBar()->height() + - 2 * SignalMargin * time_traces.size()) * 1.0 / total_rows; + + if (_session.get_device()->dev_inst()->mode == LOGIC) { + GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); + if (gvar != NULL) { + max_height = (g_variant_get_byte(gvar) + 1) * MaxHeightUnit; + g_variant_unref(gvar); + } + _signalHeight = (int)((height <= 0) ? 1 : (height >= max_height) ? max_height : height); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _signalHeight = (_header->height() + - horizontalScrollBar()->height() + - 2 * SignalMargin * time_traces.size()) * 1.0 / total_rows; + } else { + _signalHeight = (int)((height <= 0) ? 1 : height); + } + _spanY = _signalHeight + 2 * SignalMargin; + int next_v_offset = SignalMargin; + BOOST_FOREACH(boost::shared_ptr t, time_traces) { + t->set_view(this); + t->set_viewport(_time_viewport); + const double traceHeight = _signalHeight*t->rows_size(); + t->set_totalHeight((int)traceHeight); + t->set_v_offset(next_v_offset + 0.5 * traceHeight + SignalMargin); + next_v_offset += traceHeight + 2 * SignalMargin; + + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(t)) + dsoSig->set_scale(dsoSig->get_view_rect().height() / 256.0f); + } + _time_viewport->clear_measure(); + } - _viewport->clear_measure(); header_updated(); normalize_layout(); data_updated(); @@ -525,7 +646,7 @@ bool View::eventFilter(QObject *object, QEvent *event) if (type == QEvent::MouseMove) { const QMouseEvent *const mouse_event = (QMouseEvent*)event; - if (object == _ruler || object == _viewport) { + if (object == _ruler || object == _time_viewport || object == _fft_viewport) { //_hover_point = QPoint(mouse_event->x(), 0); double cur_periods = (mouse_event->pos().x() * _scale + _offset) / _ruler->get_min_period(); double integer_x = (round(cur_periods) * _ruler->get_min_period() - _offset ) / _scale; @@ -575,7 +696,7 @@ int View::headerWidth() QFont font = QApplication::font(); QFontMetrics fm(font); - const vector< boost::shared_ptr > traces(get_traces()); + const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); if (!traces.empty()){ BOOST_FOREACH(const boost::shared_ptr t, traces) { maxNameWidth = max(fm.boundingRect(t->get_name()).width(), maxNameWidth); @@ -593,8 +714,10 @@ int View::headerWidth() void View::resizeEvent(QResizeEvent*) { + setViewportMargins(headerWidth(), RulerHeight, 0, 0); update_margins(); update_scroll(); + signals_changed(); if (_session.get_device()->dev_inst()->mode == DSO) _scale = _session.get_device()->get_time_base() * std::pow(10.0, -9.0) * DS_CONF_DSO_HDIVS / get_view_width(); @@ -605,10 +728,10 @@ void View::resizeEvent(QResizeEvent*) _scale = min(_scale, _maxscale); - signals_changed(); _ruler->update(); _header->header_resize(); - _need_update = true; + set_update(_time_viewport, true); + set_update(_fft_viewport, true); } void View::h_scroll_value_changed(int value) @@ -631,15 +754,14 @@ void View::h_scroll_value_changed(int value) if (_offset != _preOffset) { _ruler->update(); - _viewport->update(); + viewport_update(); } } void View::v_scroll_value_changed(int value) { - _v_offset = value; _header->update(); - _viewport->update(); + viewport_update(); } void View::data_updated() @@ -651,18 +773,19 @@ void View::data_updated() update_scroll(); // Repaint the view - _need_update = true; - _viewport->update(); + set_update(_time_viewport, true); + set_update(_fft_viewport, true); + viewport_update(); } void View::update_margins() { - _ruler->setGeometry(_viewport->x(), 0, - get_view_width(), _viewport->y()); - _header->setGeometry(0, _viewport->y(), - _viewport->x(), _viewport->height()); + _ruler->setGeometry(_viewcenter->x(), 0, + get_view_width(), _viewcenter->y()); + _header->setGeometry(0, _viewcenter->y(), + _viewcenter->x(), _viewcenter->height()); _devmode->setGeometry(0, 0, - _viewport->x(), _viewport->y()); + _viewcenter->x(), _viewcenter->y()); } void View::header_updated() @@ -673,21 +796,21 @@ void View::header_updated() // Update the scroll bars update_scroll(); - _viewport->update(); + viewport_update(); _header->update(); } void View::marker_time_changed() { _ruler->update(); - _viewport->update(); + viewport_update(); } void View::on_traces_moved() { update_scroll(); - _need_update = true; - _viewport->update(); + set_update(_time_viewport, true); + viewport_update(); //traces_moved(); } @@ -740,9 +863,18 @@ void View::set_cursor_middle(int index) set_scale_offset(_scale, (*i)->index() * 1.0 / _session.get_device()->get_sample_rate() - _scale * get_view_width() / 2); } -Viewport * View::get_viewport() +void View::on_measure_updated() { - return _viewport; + _active_viewport = dynamic_cast(sender()); + measure_updated(); +} + +QString View::get_measure(QString option) +{ + if (_active_viewport) { + return _active_viewport->get_measure(option); + } + return "#####"; } QString View::get_cm_time(int index) @@ -782,13 +914,16 @@ void View::on_cursor_moved() void View::set_measure_en(int enable) { - _viewport->set_measure_en(enable); + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->set_measure_en(enable); } void View::on_state_changed(bool stop) { - if (stop) - _viewport->stop_trigger_timer(); + if (stop) { + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->stop_trigger_timer(); + } } int View::get_view_width() @@ -800,7 +935,7 @@ int View::get_view_width() view_width = max((double)view_width, s->get_view_rect().width()); } } else { - view_width = _viewport->width(); + view_width = _viewcenter->width(); } return view_width; @@ -815,7 +950,7 @@ int View::get_view_height() view_height = max((double)view_height, s->get_view_rect().height()); } } else { - view_height = _viewport->width(); + view_height = _viewcenter->height(); } return view_height; @@ -846,5 +981,19 @@ void View::show_region(uint64_t start, uint64_t end) set_scale_offset(new_scale, new_off); } +void View::viewport_update() +{ + _viewcenter->update(); + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->update(); +} + +void View::splitterMoved(int pos, int index) +{ + (void)pos; + (void)index; + signals_changed(); +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index 1f903737..a90f8fb4 100644 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -32,12 +32,15 @@ #include #include -#include +#include #include #include +#include +#include "../../extdef.h" #include "../toolbars/samplingbar.h" #include "../data/signaldata.h" +#include "../view/viewport.h" #include "cursor.h" #include "signal.h" @@ -57,7 +60,7 @@ class Ruler; class Trace; class Viewport; -class View : public QAbstractScrollArea { +class View : public QScrollArea { Q_OBJECT private: @@ -111,7 +114,7 @@ public: void set_scale_offset(double scale, double offset); void set_preScale_preOffset(); - std::vector< boost::shared_ptr > get_traces() const; + std::vector< boost::shared_ptr > get_traces(int type); /** * Returns true if cursors are displayed. false otherwise. @@ -164,11 +167,10 @@ public: double get_minscale() const; double get_maxscale() const; - void set_need_update(bool need_update); - bool need_update() const; + void set_update(Viewport *viewport, bool need_update); + void set_all_update(bool need_update); uint64_t get_cursor_samples(int index); - Viewport * get_viewport(); QString get_cm_time(int index); QString get_cm_delta(int index1, int index2); @@ -187,6 +189,11 @@ public: QString trigger_time(); + QString get_measure(QString option); + + void viewport_update(); + + signals: void hover_point_changed(); @@ -198,6 +205,8 @@ signals: void mode_changed(); + void measure_updated(); + private: void get_scroll_layout(double &length, double &offset) const; @@ -236,12 +245,22 @@ private slots: void set_trig_pos(quint64 trig_pos); + void on_measure_updated(); + + void splitterMoved(int pos, int index); + private: SigSession &_session; pv::toolbars::SamplingBar *_sampling_bar; - Viewport *_viewport; + QWidget *_viewcenter; + QSplitter *_vsplitter; + Viewport * _time_viewport; + Viewport * _fft_viewport; + Viewport *_active_viewport; + std::list _viewport_list; + std::map _trace_view_map; Ruler *_ruler; Header *_header; DevMode *_devmode; @@ -259,10 +278,7 @@ private: int _spanY; int _signalHeight; - int _v_offset; - bool _updating_scroll; - - bool _need_update; + bool _updating_scroll; bool _show_cursors; diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 4f5b6f67..4ecbc294 100644 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -21,13 +21,13 @@ */ -#include "view.h" #include "viewport.h" #include "ruler.h" #include "signal.h" #include "dsosignal.h" #include "logicsignal.h" +#include "mathtrace.h" #include "../device/devinst.h" #include "../data/logic.h" #include "../data/logicsnapshot.h" @@ -52,9 +52,11 @@ namespace view { const double Viewport::DragDamping = 1.05; const double Viewport::MinorDragRateUp = 10; -Viewport::Viewport(View &parent) : - QWidget(&parent), - _view(parent), +Viewport::Viewport(View &parent, View_type type) : + QWidget(&parent), + _view(parent), + _type(type), + _need_update(false), _total_receive_len(0), _action_type(NO_ACTION), _measure_type(NO_MEASURE), @@ -100,7 +102,7 @@ int Viewport::get_total_height() const { int h = 0; - const vector< boost::shared_ptr > traces(_view.get_traces()); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); h += (int)(t->get_totalHeight()); @@ -126,11 +128,13 @@ void Viewport::paintEvent(QPaintEvent *event) QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this); - const vector< boost::shared_ptr > traces(_view.get_traces()); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); t->paint_back(p, 0, _view.get_view_width()); + if (t->enabled() && _view.session().get_device()->dev_inst()->mode == DSO) + break; } p.setRenderHint(QPainter::Antialiasing, false); @@ -145,9 +149,11 @@ void Viewport::paintEvent(QPaintEvent *event) break; case SigSession::Running: - p.setRenderHint(QPainter::Antialiasing); - paintProgress(p); - p.setRenderHint(QPainter::Antialiasing, false); + if (_type == TIME_VIEW) { + p.setRenderHint(QPainter::Antialiasing); + paintProgress(p); + p.setRenderHint(QPainter::Antialiasing, false); + } break; } } else { @@ -172,11 +178,11 @@ void Viewport::paintEvent(QPaintEvent *event) void Viewport::paintSignals(QPainter &p) { - const vector< boost::shared_ptr > traces(_view.get_traces()); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); if (_view.scale() != _curScale || _view.offset() != _curOffset || _view.get_signalHeight() != _curSignalHeight || - _view.need_update()) { + _need_update) { _curScale = _view.scale(); _curOffset = _view.offset(); _curSignalHeight = _view.get_signalHeight(); @@ -190,15 +196,14 @@ void Viewport::paintSignals(QPainter &p) { assert(t); if (t->enabled()) - t->paint_mid(dbp, 0, _view.get_view_width()); + t->paint_mid(dbp, 0, t->get_view_rect().width()); } - - _view.set_need_update(false); + _need_update = false; } p.drawPixmap(0, 0, pixmap); // plot cursors - if (_view.cursors_shown()) { + if (_view.cursors_shown() && _type == TIME_VIEW) { list::iterator i = _view.get_cursorList().begin(); double cursorX; const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); @@ -212,22 +217,25 @@ void Viewport::paintSignals(QPainter &p) i++; } } - if (_view.trig_cursor_shown()) { - _view.get_trig_cursor()->paint(p, rect(), 0); - } - if (_view.search_cursor_shown()) { - _view.get_search_cursor()->paint(p, rect(), 0); - } - // plot zoom rect - if (_action_type == LOGIC_ZOOM) { - p.setPen(Qt::NoPen); - p.setBrush(Trace::dsLightBlue); - p.drawRect(QRectF(_mouse_down_point, _mouse_point)); - } + if (_type == TIME_VIEW) { + if (_view.trig_cursor_shown()) { + _view.get_trig_cursor()->paint(p, rect(), 0); + } + if (_view.search_cursor_shown()) { + _view.get_search_cursor()->paint(p, rect(), 0); + } - //plot measure arrow - paintMeasure(p); + // plot zoom rect + if (_action_type == LOGIC_ZOOM) { + p.setPen(Qt::NoPen); + p.setBrush(Trace::dsLightBlue); + p.drawRect(QRectF(_mouse_down_point, _mouse_point)); + } + + //plot measure arrow + paintMeasure(p); + } } void Viewport::paintProgress(QPainter &p) @@ -413,38 +421,51 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) _hover_hit = false; if (event->buttons() & Qt::LeftButton) { - _view.set_scale_offset(_view.scale(), - _mouse_down_offset + - (_mouse_down_point - event->pos()).x() * - _view.scale()); - _drag_strength = (_mouse_down_point - event->pos()).x(); + if (_type == TIME_VIEW) { + _view.set_scale_offset(_view.scale(), + _mouse_down_offset + + (_mouse_down_point - event->pos()).x() * + _view.scale()); + _drag_strength = (_mouse_down_point - event->pos()).x(); + } else if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + double delta = (_mouse_point - event->pos()).x(); + t->set_offset(delta); + break; + } + } + } } - if (!(event->buttons() || Qt::NoButton)) { - if (_action_type == DSO_TRIG_MOVE) { - if (_drag_sig) { - boost::shared_ptr dsoSig; - if (dsoSig = dynamic_pointer_cast(_drag_sig)) - dsoSig->set_trig_vpos(event->pos().y()); + if (_type == TIME_VIEW) { + if (!(event->buttons() || Qt::NoButton)) { + if (_action_type == DSO_TRIG_MOVE) { + if (_drag_sig) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(_drag_sig)) + dsoSig->set_trig_vpos(event->pos().y()); + } } - } - if (_action_type == CURS_MOVE) { - uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); - if (_view.cursors_shown() && grabbed_marker) { - const double cur_time = _view.offset() + _view.hover_point().x() * _view.scale(); - const double pos = cur_time * sample_rate; - const double pos_delta = pos - (uint64_t)pos; - if ( pos_delta < 0.5) - grabbed_marker->set_index((uint64_t)floor(pos)); - else - grabbed_marker->set_index((uint64_t)ceil(pos)); + if (_action_type == CURS_MOVE) { + uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); + if (_view.cursors_shown() && grabbed_marker) { + const double cur_time = _view.offset() + _view.hover_point().x() * _view.scale(); + const double pos = cur_time * sample_rate; + const double pos_delta = pos - (uint64_t)pos; + if ( pos_delta < 0.5) + grabbed_marker->set_index((uint64_t)floor(pos)); + else + grabbed_marker->set_index((uint64_t)ceil(pos)); + } } - } - if (_action_type == DSO_YM) - _dso_ym_end = event->pos().y(); + if (_action_type == DSO_YM) + _dso_ym_end = event->pos().y(); + } } _mouse_point = event->pos(); @@ -457,177 +478,178 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) { assert(event); - if ((_action_type == NO_ACTION) && - (event->button() == Qt::LeftButton)) { - // priority 0 - if (_action_type == NO_ACTION && _view.cursors_shown()) { - list::iterator i = _view.get_cursorList().begin(); - double cursorX; - const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); - while (i != _view.get_cursorList().end()) { - cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); - if ((*i)->grabbed()) { - _view.get_ruler()->rel_grabbed_cursor(); - } else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) { - _view.get_ruler()->set_grabbed_cursor(*i); - _action_type = CURS_MOVE; - break; - } - i++; - } - } - - if (_view.session().get_device()->dev_inst()->mode == LOGIC && - _view.session().get_capture_state() == SigSession::Stopped) { - // priority 1 - if (_action_type == NO_ACTION) { - const double strength = _drag_strength*DragTimerInterval*1.0/_time.elapsed(); - if (_time.elapsed() < 200 && - abs(_drag_strength) < MinorDragOffsetUp && - abs(strength) > MinorDragRateUp) { - _drag_strength = _drag_strength; - _drag_timer.start(DragTimerInterval); - _action_type = LOGIC_MOVE; - } else if (_time.elapsed() < 200 && - abs(strength) > DragTimerInterval) { - _drag_strength = strength * 5; - _drag_timer.start(DragTimerInterval); - _action_type = LOGIC_MOVE; + if (_type == TIME_VIEW) { + if ((_action_type == NO_ACTION) && + (event->button() == Qt::LeftButton)) { + // priority 0 + if (_action_type == NO_ACTION && _view.cursors_shown()) { + list::iterator i = _view.get_cursorList().begin(); + double cursorX; + const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); + while (i != _view.get_cursorList().end()) { + cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); + if ((*i)->grabbed()) { + _view.get_ruler()->rel_grabbed_cursor(); + } else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) { + _view.get_ruler()->set_grabbed_cursor(*i); + _action_type = CURS_MOVE; + break; + } + i++; } } - // priority 2 - if (_action_type == NO_ACTION) { - if (_mouse_down_point.x() == event->pos().x()) { + if (_view.session().get_device()->dev_inst()->mode == LOGIC && + _view.session().get_capture_state() == SigSession::Stopped) { + // priority 1 + if (_action_type == NO_ACTION) { + const double strength = _drag_strength*DragTimerInterval*1.0/_time.elapsed(); + if (_time.elapsed() < 200 && + abs(_drag_strength) < MinorDragOffsetUp && + abs(strength) > MinorDragRateUp) { + _drag_strength = _drag_strength; + _drag_timer.start(DragTimerInterval); + _action_type = LOGIC_MOVE; + } else if (_time.elapsed() < 200 && + abs(strength) > DragTimerInterval) { + _drag_strength = strength * 5; + _drag_timer.start(DragTimerInterval); + _action_type = LOGIC_MOVE; + } + } + + // priority 2 + if (_action_type == NO_ACTION) { + if (_mouse_down_point.x() == event->pos().x()) { + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + if (abs(event->pos().y() - s->get_y()) < _view.get_signalHeight()) { + _action_type = LOGIC_EDGE; + _edge_start = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate(); + break; + } + } + } + } + } else if (_view.session().get_device()->dev_inst()->mode == DSO) { + // priority 0 + if (_action_type == NO_ACTION && _hover_hit) { + _action_type = DSO_YM; + _dso_ym_valid = true; + _dso_ym_sig_index = _hover_sig_index; + _dso_ym_sig_value = _hover_sig_value; + _dso_ym_index = _hover_index; + _dso_ym_start = event->pos().y(); + } + + // priority 1 + if (_action_type == NO_ACTION) { const vector< boost::shared_ptr > sigs(_view.session().get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { assert(s); - if (abs(event->pos().y() - s->get_y()) < _view.get_signalHeight()) { - _action_type = LOGIC_EDGE; - _edge_start = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate(); - break; + if (!s->enabled()) + continue; + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) { + _drag_sig = s; + _action_type = DSO_TRIG_MOVE; + break; + } } } } } - } else if (_view.session().get_device()->dev_inst()->mode == DSO) { - // priority 0 - if (_action_type == NO_ACTION && _hover_hit) { - _action_type = DSO_YM; - _dso_ym_valid = true; - _dso_ym_sig_index = _hover_sig_index; - _dso_ym_sig_value = _hover_sig_value; - _dso_ym_index = _hover_index; - _dso_ym_start = event->pos().y(); + } else if (_action_type == DSO_YM) { + if (event->button() == Qt::LeftButton) { + _dso_ym_end = event->pos().y(); + _action_type = NO_ACTION; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_ym_valid = false; } + } else if (_action_type == DSO_TRIG_MOVE) { + if (event->button() == Qt::LeftButton) { + _drag_sig.reset(); + _action_type = NO_ACTION; + } + } else if (_action_type == DSO_XM_STEP0) { + if (event->button() == Qt::LeftButton) { + _action_type = DSO_XM_STEP1; + _dso_xm_valid = true; + } + } else if (_action_type == DSO_XM_STEP1) { + if (event->button() == Qt::LeftButton) { + const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + const double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; - // priority 1 - if (_action_type == NO_ACTION) { - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - assert(s); - if (!s->enabled()) - continue; - boost::shared_ptr dsoSig; - if (dsoSig = dynamic_pointer_cast(s)) { - if (dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) { - _drag_sig = s; - _action_type = DSO_TRIG_MOVE; - break; - } + _dso_xm_index[1] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + const uint64_t max_index = max(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[0] = min(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[1] = max_index; + + _action_type = DSO_XM_STEP2; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + measure_updated(); + } + } else if (_action_type == DSO_XM_STEP2) { + if (event->button() == Qt::LeftButton) { + const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + const double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; + _dso_xm_index[2] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + const uint64_t max_index = max(_dso_xm_index[1], _dso_xm_index[2]); + _dso_xm_index[1] = min(_dso_xm_index[1], _dso_xm_index[2]); + _dso_xm_index[2] = max_index; + + _action_type = NO_ACTION; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + measure_updated(); + } + } else if (_action_type == CURS_MOVE) { + _action_type = NO_ACTION; + if (_view.cursors_shown()) { + list::iterator i = _view.get_cursorList().begin(); + while (i != _view.get_cursorList().end()) { + if ((*i)->grabbed()) { + _view.get_ruler()->rel_grabbed_cursor(); } + i++; } } - } - } else if (_action_type == DSO_YM) { - if (event->button() == Qt::LeftButton) { - _dso_ym_end = event->pos().y(); + } else if (_action_type == LOGIC_EDGE) { _action_type = NO_ACTION; - } else if (event->button() == Qt::RightButton) { + _edge_rising = 0; + _edge_falling = 0; + } else if (_action_type == LOGIC_MOVE) { + _drag_strength = 0; + _drag_timer.stop(); _action_type = NO_ACTION; - _dso_ym_valid = false; - } - } else if (_action_type == DSO_TRIG_MOVE) { - if (event->button() == Qt::LeftButton) { - _drag_sig.reset(); - _action_type = NO_ACTION; - } - } else if (_action_type == DSO_XM_STEP0) { - if (event->button() == Qt::LeftButton) { - _action_type = DSO_XM_STEP1; - _dso_xm_valid = true; - } - } else if (_action_type == DSO_XM_STEP1) { - if (event->button() == Qt::LeftButton) { - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - - _dso_xm_index[1] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; - const uint64_t max_index = max(_dso_xm_index[0], _dso_xm_index[1]); - _dso_xm_index[0] = min(_dso_xm_index[0], _dso_xm_index[1]); - _dso_xm_index[1] = max_index; - - _action_type = DSO_XM_STEP2; - } else if (event->button() == Qt::RightButton) { - _action_type = NO_ACTION; - _dso_xm_valid = false; - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; - measure_updated(); - } - } else if (_action_type == DSO_XM_STEP2) { - if (event->button() == Qt::LeftButton) { - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - _dso_xm_index[2] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; - const uint64_t max_index = max(_dso_xm_index[1], _dso_xm_index[2]); - _dso_xm_index[1] = min(_dso_xm_index[1], _dso_xm_index[2]); - _dso_xm_index[2] = max_index; - - _action_type = NO_ACTION; - } else if (event->button() == Qt::RightButton) { - _action_type = NO_ACTION; - _dso_xm_valid = false; - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; - measure_updated(); - } - } else if (_action_type == CURS_MOVE) { - _action_type = NO_ACTION; - if (_view.cursors_shown()) { - list::iterator i = _view.get_cursorList().begin(); - while (i != _view.get_cursorList().end()) { - if ((*i)->grabbed()) { - _view.get_ruler()->rel_grabbed_cursor(); - } - i++; + } else if (_action_type == LOGIC_ZOOM) { + if (event->pos().x() != _mouse_down_point.x()) { + const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale(); + const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(), + _view.get_maxscale()), _view.get_minscale()); + if (newScale != _view.scale()) + _view.set_scale_offset(newScale, newOffset); } + _action_type = NO_ACTION; } - } else if (_action_type == LOGIC_EDGE) { - _action_type = NO_ACTION; - _edge_rising = 0; - _edge_falling = 0; - } else if (_action_type == LOGIC_MOVE) { - _drag_strength = 0; - _drag_timer.stop(); - _action_type = NO_ACTION; - } else if (_action_type == LOGIC_ZOOM) { - if (event->pos().x() != _mouse_down_point.x()) { - const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale(); - const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(), - _view.get_maxscale()), _view.get_minscale()); - if (newScale != _view.scale()) - _view.set_scale_offset(newScale, newOffset); - } - _action_type = NO_ACTION; } - update(); } @@ -676,16 +698,26 @@ void Viewport::wheelEvent(QWheelEvent *event) { assert(event); - if (event->orientation() == Qt::Vertical) { - // Vertical scrolling is interpreted as zooming in/out - const double offset = event->x(); - _view.zoom(event->delta() / 80, offset); - } else if (event->orientation() == Qt::Horizontal) { - // Horizontal scrolling is interpreted as moving left/right - _view.set_scale_offset(_view.scale(), - event->delta() * _view.scale() - + _view.offset()); - } + if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + t->zoom(event->delta() / 80, event->x()); + break; + } + } + } else if (_type == TIME_VIEW){ + if (event->orientation() == Qt::Vertical) { + // Vertical scrolling is interpreted as zooming in/out + const double offset = event->x(); + _view.zoom(event->delta() / 80, offset); + } else if (event->orientation() == Qt::Horizontal) { + // Horizontal scrolling is interpreted as moving left/right + _view.set_scale_offset(_view.scale(), + event->delta() * _view.scale() + + _view.offset()); + } + } measure(); } @@ -759,62 +791,72 @@ void Viewport::clear_measure() void Viewport::measure() { _measure_type = NO_MEASURE; - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - assert(s); - boost::shared_ptr logicSig; - boost::shared_ptr dsoSig; - if (logicSig = dynamic_pointer_cast(s)) { - if (_action_type == NO_ACTION) { - if (logicSig->measure(_mouse_point, _cur_sample, _nxt_sample, _thd_sample)) { - _measure_type = LOGIC_FREQ; + if (_type == TIME_VIEW) { + const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + boost::shared_ptr logicSig; + boost::shared_ptr dsoSig; + if (logicSig = dynamic_pointer_cast(s)) { + if (_action_type == NO_ACTION) { + if (logicSig->measure(_mouse_point, _cur_sample, _nxt_sample, _thd_sample)) { + _measure_type = LOGIC_FREQ; - _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate); - _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####"; - _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####"; + _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate); + _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####"; + _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####"; - const double pixels_offset = _view.offset() / _view.scale(); - const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _cur_sample / samples_per_pixel - pixels_offset; - _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset; - _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset; - _cur_midY = logicSig->get_y(); + const double pixels_offset = _view.offset() / _view.scale(); + const double samples_per_pixel = sample_rate * _view.scale(); + _cur_preX = _cur_sample / samples_per_pixel - pixels_offset; + _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset; + _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset; + _cur_midY = logicSig->get_y(); - _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" : - "#####"; + _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" : + "#####"; + break; + } else { + _measure_type = NO_MEASURE; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + } + } else if (_action_type == LOGIC_EDGE) { + if (logicSig->edges(_view.hover_point(), _edge_start, _edge_rising, _edge_falling)) { + const double pixels_offset = _view.offset() / _view.scale(); + const double samples_per_pixel = sample_rate * _view.scale(); + _cur_preX = _edge_start / samples_per_pixel - pixels_offset; + _cur_aftX = _view.hover_point().x(); + _cur_midY = logicSig->get_y() - logicSig->get_totalHeight()/2 - 5; + + _em_rising = "Rising: " + QString::number(_edge_rising); + _em_falling = "Falling: " + QString::number(_edge_falling); + _em_edges = "Edges: " + QString::number(_edge_rising + _edge_falling); + + break; + } + } + } else if (dsoSig = dynamic_pointer_cast(s)) { + if (_measure_en && dsoSig->measure(_view.hover_point())) { + _measure_type = DSO_VALUE; break; } else { _measure_type = NO_MEASURE; - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; - } - } else if (_action_type == LOGIC_EDGE) { - if (logicSig->edges(_view.hover_point(), _edge_start, _edge_rising, _edge_falling)) { - const double pixels_offset = _view.offset() / _view.scale(); - const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _edge_start / samples_per_pixel - pixels_offset; - _cur_aftX = _view.hover_point().x(); - _cur_midY = logicSig->get_y() - logicSig->get_totalHeight()/2 - 5; - - _em_rising = "Rising: " + QString::number(_edge_rising); - _em_falling = "Falling: " + QString::number(_edge_falling); - _em_edges = "Edges: " + QString::number(_edge_rising + _edge_falling); - - break; } } - } else if (dsoSig = dynamic_pointer_cast(s)) { - if (_measure_en && dsoSig->measure(_view.hover_point())) { - _measure_type = DSO_VALUE; - break; - } else { - _measure_type = NO_MEASURE; + } + } else if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + t->measure(_view.hover_point()); } } } + measure_updated(); } @@ -1065,7 +1107,7 @@ void Viewport::paintMeasure(QPainter &p) p.drawLine(x[dso_xm_stage-1], _dso_xm_y, _mouse_point.x(), _dso_xm_y); p.drawLine(_mouse_point.x(), 0, - _mouse_point.x(), _view.get_viewport()->height()); + _mouse_point.x(), height()); } measure_updated(); } @@ -1179,5 +1221,11 @@ void Viewport::paintTrigTime(QPainter &p) } } +void Viewport::set_need_update(bool update) +{ + _need_update = update; +} + + } // namespace view } // namespace pv diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index 999c72a9..33ed45b2 100644 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -30,8 +30,12 @@ #include #include #include + #include +#include "../../extdef.h" +#include "../view/view.h" + class QPainter; class QPaintEvent; class SigSession; @@ -81,7 +85,7 @@ public: }; public: - explicit Viewport(View &parent); + explicit Viewport(View &parent, View_type type); int get_total_height() const; @@ -96,6 +100,8 @@ public: void clear_measure(); + void set_need_update(bool update); + protected: void paintEvent(QPaintEvent *event); @@ -125,6 +131,8 @@ signals: private: View &_view; + View_type _type; + bool _need_update; uint64_t _total_receive_len; QPoint _mouse_point; diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c index a31467a5..d39aebf0 100644 --- a/libsigrok4DSL/hardware/demo/demo.c +++ b/libsigrok4DSL/hardware/demo/demo.c @@ -247,6 +247,9 @@ static const uint64_t samplerates[] = { // SR_MB(4), // SR_MB(8), // SR_MB(16), +// SR_MB(32), +// SR_MB(64), +// SR_MB(128), //}; static const uint64_t samplecounts[] = { @@ -270,10 +273,10 @@ static const uint64_t samplecounts[] = { /* We name the probes 0-7 on our demo driver. */ static const char *probe_names[NUM_PROBES + 1] = { - "Channel 0", "Channel 1", "Channel 2", "Channel 3", - "Channel 4", "Channel 5", "Channel 6", "Channel 7", - "Channel 8", "Channel 9", "Channel 10", "Channel 11", - "Channel 12", "Channel 13", "Channel 14", "Channel 15", + "CH0", "CH1", "CH2", "CH3", + "CH4", "CH5", "CH6", "CH7", + "CH8", "CH9", "CH10", "CH11", + "CH12", "CH13", "CH14", "CH15", NULL, }; diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index e55adbb0..c6c9e01e 100644 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -549,6 +549,7 @@ enum { SR_CHANNEL_ANALOG, SR_CHANNEL_GROUP, SR_CHANNEL_DECODER, + SR_CHANNEL_FFT, }; enum { @@ -560,7 +561,7 @@ enum { struct sr_channel { /* The index field will go: use g_slist_length(sdi->channels) instead. */ uint16_t index; - int type; + int type; gboolean enabled; char *name; char *trigger;