Add FFT function @ DSO mode

This commit is contained in:
DreamSourceLab 2016-05-14 10:24:44 +08:00
parent ced33961c7
commit f8b2d1e4ee
57 changed files with 2211 additions and 479 deletions

View File

@ -57,5 +57,16 @@
<file>icons/start_dis_cn.png</file>
<file>icons/settings.png</file>
<file>darkstyle/style.qss</file>
<file>icons/export.png</file>
<file>icons/single.png</file>
<file>icons/single_dis.png</file>
<file>icons/math.png</file>
<file>icons/math_dis.png</file>
<file>icons/fft.png</file>
<file>icons/Blackman.png</file>
<file>icons/Flat_top.png</file>
<file>icons/Hamming.png</file>
<file>icons/Hann.png</file>
<file>icons/Rectangle.png</file>
</qresource>
</RCC>

View File

@ -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

BIN
DSView/icons/about.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 942 B

After

Width:  |  Height:  |  Size: 919 B

BIN
DSView/icons/file.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
DSView/icons/file_dis.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
DSView/icons/instant.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
DSView/icons/measure.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
DSView/icons/measure_dis.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1002 B

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
DSView/icons/params.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
DSView/icons/params_dis.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
DSView/icons/protocol.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 967 B

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
DSView/icons/protocol_cn.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
DSView/icons/protocol_dis.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 931 B

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
DSView/icons/search-bar.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
DSView/icons/search-bar_dis.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
DSView/icons/start.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
DSView/icons/stop.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
DSView/icons/trigger.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 840 B

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
DSView/icons/trigger_dis.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 B

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
DSView/icons/wiki.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,7 +1,241 @@
#include "fftstack.h"
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* 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 <boost/foreach.hpp>
#include <boost/thread/thread.hpp>
#include <pv/data/dso.h>
#include <pv/data/dsosnapshot.h>
#include <pv/sigsession.h>
#include <pv/view/dsosignal.h>
#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<QString> MathStack::get_windows_support() const
{
std::vector<QString> 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<uint64_t> MathStack::get_length_support() const
{
std::vector<uint64_t> 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<double> MathStack::get_fft_spectrum() const
{
std::vector<double> 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<pv::data::Dso> data;
boost::shared_ptr<pv::view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<view::Signal> s, _session.get_signals()) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(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<pv::data::DsoSnapshot> > &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

View File

@ -1,11 +1,119 @@
#ifndef FFTSTACK_H
#define FFTSTACK_H
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* 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 <list>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <fftw3.h>
#include <QObject>
#include <QString>
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<QString> get_windows_support() const;
const std::vector<uint64_t> 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<double> 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<pv::data::DsoSnapshot> _snapshot;
std::unique_ptr<boost::thread> _math_thread;
math_state _math_state;
fftw_plan _fft_plan;
std::vector<double> _xn;
std::vector<double> _xk;
std::vector<double> _power_spectrum;
};
#endif // FFTSTACK_H
} // namespace data
} // namespace pv
#endif // DSVIEW_PV_DATA_MATHSTACK_H

View File

@ -1,7 +1,257 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
* Copyright (C) 2013 DreamSourceLab <dreamsourcelab@dreamsourcelab.com>
*
* 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 <boost/foreach.hpp>
#include <QFormLayout>
#include <QListWidget>
#include <QMessageBox>
#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<view::Signal> s, _session.get_signals()) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(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<QString> windows;
std::vector<uint64_t> length;
std::vector<QString> view_modes;
std::vector<int> dbv_ranges;
BOOST_FOREACH(const boost::shared_ptr<view::Trace> t, _session.get_math_signals()) {
boost::shared_ptr<view::MathTrace> mathTrace;
if (mathTrace = dynamic_pointer_cast<view::MathTrace>(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<view::Trace> t, _session.get_math_signals()) {
boost::shared_ptr<view::MathTrace> mathTrace;
if (mathTrace = dynamic_pointer_cast<view::MathTrace>(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<view::Trace> t, _session.get_math_signals()) {
boost::shared_ptr<view::MathTrace> mathTrace;
if (mathTrace = dynamic_pointer_cast<view::MathTrace>(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

View File

@ -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 <joel@airwebreathe.org.uk>
* Copyright (C) 2013 DreamSourceLab <dreamsourcelab@dreamsourcelab.com>
*
* 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 <QDialog>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QCheckBox>
#include <QComboBox>
#include <boost/shared_ptr.hpp>
#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

View File

@ -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()

View File

@ -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<pv::device::DevInst> 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
}

View File

@ -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 <assert.h>
#include <stdexcept>
@ -496,7 +498,6 @@ set< boost::shared_ptr<data::SignalData> > 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<view::MathTrace> 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<view::Signal> >().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<view::MathTrace> 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<view::Signal> s, _signals) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)) {
has_dso_signal = true;
// check already have
std::vector< boost::shared_ptr<view::MathTrace> >::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<data::MathStack> math_stack(
new data::MathStack(*this, dsoSig->get_index()));
boost::shared_ptr<view::MathTrace> 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<view::MathTrace> > SigSession::get_math_signals()
{
lock_guard<mutex> lock(_signals_mutex);
return _math_traces;
}
} // namespace pv

View File

@ -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<view::MathTrace> >
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<view::DecodeTrace> > _decode_traces;
pv::data::DecoderModel *_decoder_model;
#endif
std::vector< boost::shared_ptr<view::MathTrace> > _math_traces;
mutable boost::mutex _data_mutex;
boost::shared_ptr<data::Logic> _logic_data;

View File

@ -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()));

View File

@ -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

View File

@ -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;
};

View File

@ -22,19 +22,27 @@
#include "trigbar.h"
#include "../sigsession.h"
#include "../device/devinst.h"
#include "../dialogs/fftoptions.h"
#include <QApplication>
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

View File

@ -26,19 +26,25 @@
#include <QToolBar>
#include <QToolButton>
#include <QAction>
#include <QMenu>
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;
};

View File

@ -54,7 +54,7 @@ const float AnalogSignal::EnvelopeThreshold = 256.0f;
AnalogSignal::AnalogSignal(boost::shared_ptr<pv::device::DevInst> dev_inst,
boost::shared_ptr<data::Analog> 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)];

View File

@ -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();

View File

@ -24,6 +24,7 @@
#include <math.h>
#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<pv::device::DevInst> dev_inst,
boost::shared_ptr<data::Dso> 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<pv::data::SignalData> DsoSignal::data() const
return _data;
}
void DsoSignal::set_view(pv::view::View *view)
boost::shared_ptr<pv::data::Dso> 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<Trace> > traces(_view->get_traces());
const vector< boost::shared_ptr<Trace> > 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<Trace> > 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<Trace> > traces(_view->get_traces());
const vector< boost::shared_ptr<Trace> > 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;
}

View File

@ -105,7 +105,8 @@ public:
virtual ~DsoSignal();
boost::shared_ptr<pv::data::SignalData> data() const;
void set_view(pv::view::View *view);
boost::shared_ptr<pv::data::Dso> 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.
*/

View File

@ -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<pv::view::Trace> Header::get_mTrace(
{
const int w = width();
const vector< boost::shared_ptr<Trace> > traces(
_view.get_traces());
_view.get_traces(ALL_VIEW));
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
@ -120,7 +121,7 @@ void Header::paintEvent(QPaintEvent*)
const int w = width();
const vector< boost::shared_ptr<Trace> > traces(
_view.get_traces());
_view.get_traces(ALL_VIEW));
const bool dragging = !_drag_traces.empty();
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
@ -137,7 +138,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event)
assert(event);
const vector< boost::shared_ptr<Trace> > 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<Trace> > 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<Trace> > traces(
_view.get_traces());
_view.get_traces(ALL_VIEW));
// Vertical scrolling
double shift = event->delta() / 20.0;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)

View File

@ -52,7 +52,7 @@ const int LogicSignal::StateRound = 5;
LogicSignal::LogicSignal(boost::shared_ptr<pv::device::DevInst> dev_inst,
boost::shared_ptr<data::Logic> data,
const sr_channel * const probe) :
Signal(dev_inst, probe, SR_CHANNEL_LOGIC),
Signal(dev_inst, probe),
_data(data),
_trig(NONTRIG)
{

View File

@ -1,7 +1,488 @@
#include "ffttrace.h"
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* 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 <extdef.h>
#include "mathtrace.h"
FftTrace::FftTrace()
#include <algorithm>
#include <math.h>
#include <boost/foreach.hpp>
#include <boost/functional/hash.hpp>
#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<pv::data::MathStack> 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<Signal> > sigs(_session.get_signals());
for(size_t i = 0; i < sigs.size(); i++) {
const boost::shared_ptr<view::Signal> s(sigs[i]);
assert(s);
if (dynamic_pointer_cast<DsoSignal>(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<QString> MathTrace::get_view_modes_support()
{
std::vector<QString> 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<pv::data::MathStack>& 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<int> MathTrace::get_dbv_ranges()
{
std::vector<int> 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<double> 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<double> 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<Signal> s, _session.get_signals()) {
boost::shared_ptr<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(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<right && sample < samples.size());
p.drawPolyline(points, point - points);
delete[] points;
}
}
void MathTrace::paint_fore(QPainter &p, int left, int right)
{
using namespace Qt;
if(!_view)
return;
assert(right >= 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<double> 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

View File

@ -1,11 +1,156 @@
#ifndef FFTTRACE_H
#define FFTTRACE_H
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* 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 <list>
#include <map>
#include <boost/shared_ptr.hpp>
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<pv::data::MathStack> 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<int> get_dbv_ranges();
int view_mode() const;
void set_view_mode(int mode);
std::vector<QString> get_view_modes_support();
const boost::shared_ptr<pv::data::MathStack>& 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<pv::data::MathStack> _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

View File

@ -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;
}

View File

@ -35,8 +35,8 @@ namespace pv {
namespace view {
Signal::Signal(boost::shared_ptr<pv::device::DevInst> 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)
{

View File

@ -57,7 +57,7 @@ private:
protected:
Signal(boost::shared_ptr<pv::device::DevInst> dev_inst,
const sr_channel * const probe, int type);
const sr_channel * const probe);
/**
* Copy constructor

View File

@ -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

View File

@ -31,6 +31,8 @@
#include <stdint.h>
#include <libsigrok4DSL/libsigrok.h>
#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;

View File

@ -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<Trace> > View::get_traces() const
vector< boost::shared_ptr<Trace> > View::get_traces(int type)
{
// const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
// const vector< boost::shared_ptr<GroupSignal> > groups(_session.get_group_signals());
//#ifdef ENABLE_DECODE
// const vector< boost::shared_ptr<DecodeTrace> > decode_sigs(
// _session.get_decode_signals());
// vector< boost::shared_ptr<Trace> > traces(
// sigs.size() + groups.size() + decode_sigs.size());
//#else
// vector< boost::shared_ptr<Trace> > traces(sigs.size() + groups.size());
//#endif
// vector< boost::shared_ptr<Trace> >::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<Signal> > sigs(_session.get_signals());
const vector< boost::shared_ptr<GroupSignal> > groups(_session.get_group_signals());
#ifdef ENABLE_DECODE
const vector< boost::shared_ptr<DecodeTrace> > decode_sigs(
_session.get_decode_signals());
vector< boost::shared_ptr<Trace> > traces(
sigs.size() + groups.size() + decode_sigs.size());
#else
vector< boost::shared_ptr<Trace> > traces(sigs.size() + groups.size());
#endif
const vector< boost::shared_ptr<MathTrace> > maths(_session.get_math_signals());
vector< boost::shared_ptr<Trace> >::iterator i = traces.begin();
i = copy(sigs.begin(), sigs.end(), i);
vector< boost::shared_ptr<Trace> > traces;
BOOST_FOREACH(boost::shared_ptr<Trace> 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<Trace> 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<Trace> t, groups) {
if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type)
traces.push_back(t);
}
BOOST_FOREACH(boost::shared_ptr<Trace> 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<Trace> > traces(get_traces());
const vector< boost::shared_ptr<Trace> > traces(get_traces(ALL_VIEW));
int v_min = INT_MAX;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
@ -395,7 +471,7 @@ void View::normalize_layout()
BOOST_FOREACH(boost::shared_ptr<Trace> 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<Trace> > traces(get_traces());
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (dynamic_pointer_cast<DsoSignal>(t) ||
t->enabled())
total_rows += t->rows_size();
vector< boost::shared_ptr<Trace> > time_traces;
vector< boost::shared_ptr<Trace> > fft_traces;
BOOST_FOREACH(const boost::shared_ptr<Trace> 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<Trace> 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<Trace> 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<Trace> t, time_traces) {
assert(t);
if (dynamic_pointer_cast<DsoSignal>(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<Trace> 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<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(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<Trace> > traces(get_traces());
const vector< boost::shared_ptr<Trace> > traces(get_traces(ALL_VIEW));
if (!traces.empty()){
BOOST_FOREACH(const boost::shared_ptr<Trace> 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<Viewport *>(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

View File

@ -32,12 +32,15 @@
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <QAbstractScrollArea>
#include <QScrollArea>
#include <QSizeF>
#include <QDateTime>
#include <QSplitter>
#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<Trace> > get_traces() const;
std::vector< boost::shared_ptr<Trace> > 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 *> _viewport_list;
std::map<int, int> _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;

View File

@ -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<Trace> > traces(_view.get_traces());
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces(_type));
BOOST_FOREACH(const boost::shared_ptr<Trace> 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<Trace> > traces(_view.get_traces());
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces(_type));
BOOST_FOREACH(const boost::shared_ptr<Trace> 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<Trace> > traces(_view.get_traces());
const vector< boost::shared_ptr<Trace> > 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<Cursor*>::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<view::MathTrace> 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<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(_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<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(_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<Cursor*>::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<Cursor*>::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<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> 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<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> 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<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(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<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
assert(s);
if (!s->enabled())
continue;
boost::shared_ptr<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(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<Cursor*>::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<Cursor*>::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<view::MathTrace> 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<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
assert(s);
boost::shared_ptr<view::LogicSignal> logicSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (logicSig = dynamic_pointer_cast<view::LogicSignal>(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<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
assert(s);
boost::shared_ptr<view::LogicSignal> logicSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (logicSig = dynamic_pointer_cast<view::LogicSignal>(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<view::DsoSignal>(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<view::DsoSignal>(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<view::MathTrace> 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

View File

@ -30,8 +30,12 @@
#include <QTime>
#include <QTimer>
#include <QWidget>
#include <stdint.h>
#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;

View File

@ -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,
};

View File

@ -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;