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