2
0
forked from Ivasoft/DSView
Files
DSView/DSView/pv/dialogs/deviceoptions.cpp
2022-04-26 11:34:18 +08:00

568 lines
18 KiB
C++
Executable File

/*
* 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 <support@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 "deviceoptions.h"
#include <QListWidget>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include "dsmessagebox.h"
#include "../prop/property.h"
#include "../dsvdef.h"
using namespace boost;
using namespace std;
namespace pv {
namespace dialogs {
DeviceOptions::DeviceOptions(QWidget *parent, DevInst *dev_inst) :
DSDialog(parent),
_dev_inst(dev_inst),
_button_box(QDialogButtonBox::Ok, Qt::Horizontal, this),
_device_options_binding(_dev_inst->dev_inst())
{
_dynamic_box = NULL;
_props_box = NULL;
_config_button = NULL;
_cali_button = NULL;
QWidget *dlg = this;
setTitle(tr("Device Options"));
_props_box = new QGroupBox(tr("Mode"), this);
_props_box->setLayout(get_property_form(_props_box));
_layout.addWidget(_props_box);
_dynamic_box = new QGroupBox(dynamic_widget(_dynamic_layout),this);
_dynamic_box->setLayout(&_dynamic_layout);
_layout.addWidget(_dynamic_box);
_dynamic_box->setVisible(_dynamic_box->title() != "");
_layout.addStretch(1);
_layout.addWidget(&_button_box);
layout()->addLayout(&_layout);
connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept()));
connect(_dev_inst, SIGNAL(device_updated()), this, SLOT(reject()));
GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_OPERATION_MODE);
if (gvar != NULL) {
_mode = QString::fromUtf8(g_variant_get_string(gvar, NULL));
g_variant_unref(gvar);
}
connect(&_mode_check, SIGNAL(timeout()), this, SLOT(mode_check()));
_mode_check.setInterval(100);
_mode_check.start();
}
DeviceOptions::~DeviceOptions(){
DESTROY_QT_OBJECT(_dynamic_box);
DESTROY_QT_OBJECT(_props_box);
DESTROY_QT_OBJECT(_config_button);
DESTROY_QT_OBJECT(_cali_button);
}
void DeviceOptions::accept()
{
using namespace Qt;
bool hasEnabled = false;
// Commit the properties
const auto &dev_props = _device_options_binding.properties();
for(auto &p : dev_props) {
assert(p);
p->commit();
}
// Commit the probes
if (_dev_inst->dev_inst()->mode == LOGIC ||
_dev_inst->dev_inst()->mode == ANALOG) {
int index = 0;
for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) {
sr_channel *const probe = (sr_channel*)l->data;
assert(probe);
probe->enabled = _probes_checkBox_list.at(index)->isChecked();
index++;
if (probe->enabled)
hasEnabled = true;
}
} else {
hasEnabled = true;
}
if (hasEnabled) {
QVector<pv::prop::binding::ProbeOptions *>::iterator i = _probe_options_binding_list.begin();
while(i != _probe_options_binding_list.end()) {
const auto &probe_props = (*i)->properties();
for(auto &p :probe_props) {
assert(p);
p->commit();
}
i++;
}
QDialog::accept();
} else {
dialogs::DSMessageBox msg(this);
msg.mBox()->setText(tr("Attention"));
msg.mBox()->setInformativeText(tr("All channel disabled! Please enable at least one channel."));
msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole);
msg.mBox()->setIcon(QMessageBox::Warning);
msg.exec();
}
}
void DeviceOptions::reject()
{
using namespace Qt;
QDialog::reject();
}
QGridLayout * DeviceOptions::get_property_form(QWidget * parent)
{
QGridLayout *const layout = new QGridLayout(parent);
layout->setVerticalSpacing(5);
const auto &properties =_device_options_binding.properties();
int i = 0;
for(auto &p : properties)
{
assert(p);
const QString label = p->labeled_widget() ? QString() : p->label();
layout->addWidget(new QLabel(label, parent), i, 0);
if (label == tr("Operation Mode"))
layout->addWidget(p->get_widget(parent, true), i, 1);
else
layout->addWidget(p->get_widget(parent), i, 1);
i++;
}
return layout;
}
void DeviceOptions::logic_probes(QGridLayout &layout)
{
using namespace Qt;
int row0 = 0, row1 = 0, col = 0;
int index = 0;
QString ch_mode;
int vld_ch_num = 0;
int cur_ch_num = 0;
while(layout.count() > 0)
{
//remove Widgets in QLayoutGrid
QWidget* widget = layout.itemAt(0)->widget();
layout.removeWidget(widget);
delete widget;
}
_probes_label_list.clear();
_probes_checkBox_list.clear();
if (_dev_inst->dev_inst()->mode == LOGIC) {
GVariant *gvar_opts;
gsize num_opts;
if (sr_config_list(_dev_inst->dev_inst()->driver, _dev_inst->dev_inst(), NULL, SR_CONF_CHANNEL_MODE,
&gvar_opts) == SR_OK) {
const char **const options = g_variant_get_strv(gvar_opts, &num_opts);
GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_CHANNEL_MODE);
if (gvar != NULL) {
ch_mode = QString::fromUtf8(g_variant_get_string(gvar, NULL));
g_variant_unref(gvar);
for (unsigned int i=0; i<num_opts; i++){
QRadioButton *ch_opts = new QRadioButton(options[i]);
layout.addWidget(ch_opts, row0, col, 1, 8);
connect(ch_opts, SIGNAL(pressed()), this, SLOT(channel_check()));
row0++;
if (QString::fromUtf8(options[i]) == ch_mode)
ch_opts->setChecked(true);
}
}
if (gvar_opts)
g_variant_unref(gvar_opts);
}
}
GVariant *gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_VLD_CH_NUM);
if (gvar != NULL) {
vld_ch_num = g_variant_get_int16(gvar);
g_variant_unref(gvar);
}
for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) {
sr_channel *const probe = (sr_channel*)l->data;
assert(probe);
if (probe->enabled)
cur_ch_num++;
if (cur_ch_num > vld_ch_num)
probe->enabled = false;
QLabel *probe_label = new QLabel(QString::number(probe->index), this);
QCheckBox *probe_checkBox = new QCheckBox(this);
probe_checkBox->setCheckState(probe->enabled ? Qt::Checked : Qt::Unchecked);
layout.addWidget(probe_label, row1 * 2 + row0, col);
layout.addWidget(probe_checkBox, row1 * 2 + 1 + row0, col);
_probes_label_list.push_back(probe_label);
_probes_checkBox_list.push_back(probe_checkBox);
index++;
col = index % 8;
row1 = index / 8;
connect(probe_checkBox, SIGNAL(released()), this, SLOT(channel_enable()));
}
QPushButton *_enable_all_probes = new QPushButton(tr("Enable All"), this);
QPushButton *_disable_all_probes = new QPushButton(tr("Disable All"), this);
connect(_enable_all_probes, SIGNAL(clicked()),
this, SLOT(enable_all_probes()));
connect(_disable_all_probes, SIGNAL(clicked()),
this, SLOT(disable_all_probes()));
layout.addWidget(_enable_all_probes, (row1 + 1) * 2 + row0, 0, 1, 4);
layout.addWidget(_disable_all_probes, (row1 + 1) * 2 + row0, 4, 1, 4);
}
void DeviceOptions::set_all_probes(bool set)
{
QVector<QCheckBox *>::iterator i = _probes_checkBox_list.begin();
while(i != _probes_checkBox_list.end()) {
(*i)->setCheckState(set ? Qt::Checked : Qt::Unchecked);
i++;
}
}
void DeviceOptions::enable_max_probes() {
int cur_ch_num = 0;
QVector<QCheckBox *>::iterator iter = _probes_checkBox_list.begin();
while(iter != _probes_checkBox_list.end()) {
if ((*iter)->isChecked())
cur_ch_num++;
iter++;
}
GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_VLD_CH_NUM);
if (gvar == NULL)
return;
int vld_ch_num = g_variant_get_int16(gvar);
g_variant_unref(gvar);
iter = _probes_checkBox_list.begin();
while(cur_ch_num < vld_ch_num &&
iter != _probes_checkBox_list.end()) {
if (!(*iter)->isChecked()) {
(*iter)->setChecked(true);
cur_ch_num++;
}
iter++;
}
}
void DeviceOptions::enable_all_probes()
{
GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_STREAM);
if (gvar != NULL) {
bool stream_mode = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (stream_mode) {
enable_max_probes();
return;
}
}
set_all_probes(true);
}
void DeviceOptions::disable_all_probes()
{
set_all_probes(false);
}
void DeviceOptions::zero_adj()
{
using namespace Qt;
QDialog::accept();
dialogs::DSMessageBox msg(this);
msg.mBox()->setText(tr("Information"));
msg.mBox()->setInformativeText(tr("Auto Calibration program will be started. Don't connect any probes. It can take a while!"));
msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole);
msg.mBox()->addButton(tr("Cancel"), QMessageBox::RejectRole);
msg.mBox()->setIcon(QMessageBox::Information);
if (msg.exec()) {
_dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(true));
} else {
_dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false));
}
}
void DeviceOptions::on_calibration()
{
using namespace Qt;
QDialog::accept();
_dev_inst->set_config(NULL, NULL, SR_CONF_CALI, g_variant_new_boolean(true));
}
void DeviceOptions::mode_check()
{
bool test;
QString mode;
GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_OPERATION_MODE);
if (gvar != NULL) {
mode = QString::fromUtf8(g_variant_get_string(gvar, NULL));
g_variant_unref(gvar);
if (mode != _mode) {
dynamic_widget(_dynamic_layout);
_dynamic_box->setVisible(_dynamic_box->title() != "");
_mode = mode;
}
}
gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_TEST);
if (gvar != NULL) {
test = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (test) {
QVector<QCheckBox *>::iterator i = _probes_checkBox_list.begin();
while(i != _probes_checkBox_list.end()) {
(*i)->setCheckState(Qt::Checked);
(*i)->setDisabled(TRUE);
i++;
}
}
}
}
void DeviceOptions::channel_check()
{
QRadioButton* sc=dynamic_cast<QRadioButton*>(sender());
QString text = sc->text();
text.remove('&');
if(sc != NULL)
_dev_inst->set_config(NULL, NULL, SR_CONF_CHANNEL_MODE, g_variant_new_string(text.toUtf8().data()));
dynamic_widget(_dynamic_layout);
_dynamic_box->setVisible(_dynamic_box->title() != "");
}
void DeviceOptions::analog_channel_check()
{
QCheckBox* sc=dynamic_cast<QCheckBox*>(sender());
if(sc != NULL) {
for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) {
sr_channel *const probe = (sr_channel*)l->data;
assert(probe);
if (sc->property("index").toInt() == probe->index)
_dev_inst->set_config(probe, NULL, SR_CONF_PROBE_MAP_DEFAULT,
g_variant_new_boolean(sc->isChecked()));
}
}
dynamic_widget(_dynamic_layout);
_dynamic_box->setVisible(_dynamic_box->title() != "");
}
void DeviceOptions::channel_enable()
{
if (_dev_inst->dev_inst()->mode == LOGIC) {
QCheckBox* sc=dynamic_cast<QCheckBox*>(sender());
if (sc == NULL || !sc->isChecked())
return;
GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_STREAM);
if (gvar == NULL)
return;
bool stream_mode = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (!stream_mode)
return;
int cur_ch_num = 0;
QVector<QCheckBox *>::iterator i = _probes_checkBox_list.begin();
while(i != _probes_checkBox_list.end()) {
if ((*i)->isChecked())
cur_ch_num++;
i++;
}
gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_VLD_CH_NUM);
if (gvar == NULL)
return;
int vld_ch_num = g_variant_get_int16(gvar);
g_variant_unref(gvar);
if (cur_ch_num > vld_ch_num) {
dialogs::DSMessageBox msg(this);
msg.mBox()->setText(tr("Information"));
msg.mBox()->setInformativeText(tr("Current mode only suppport max ") + QString::number(vld_ch_num) + tr(" channels!"));
msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole);
msg.mBox()->setIcon(QMessageBox::Information);
msg.exec();
sc->setChecked(false);
}
} else if (_dev_inst->dev_inst()->mode == ANALOG) {
QCheckBox* sc=dynamic_cast<QCheckBox*>(sender());
if (sc != NULL) {
QGridLayout *const layout = (QGridLayout *)sc->property("Layout").value<void *>();
int i = layout->count();
while(i--)
{
QWidget* w = layout->itemAt(i)->widget();
if (w->property("Enable").isNull()) {
w->setEnabled(sc->isChecked());
}
}
}
}
}
QString DeviceOptions::dynamic_widget(QGridLayout& inner_layout) {
if (_dev_inst->dev_inst()->mode == LOGIC) {
logic_probes(inner_layout);
return tr("Channels");
} else if (_dev_inst->dev_inst()->mode == DSO) {
GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_HAVE_ZERO);
if (gvar != NULL) {
bool have_zero = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (have_zero) {
_config_button = new QPushButton(tr("Auto Calibration"), this);
inner_layout.addWidget(_config_button, 0, 0, 1, 1);
connect(_config_button, SIGNAL(clicked()), this, SLOT(zero_adj()));
_cali_button = new QPushButton(tr("Manual Calibration"), this);
inner_layout.addWidget(_cali_button, 1, 0, 1, 1);
connect(_cali_button, SIGNAL(clicked()), this, SLOT(on_calibration()));
return tr("Calibration");
}
}
} else if (_dev_inst->dev_inst()->mode == ANALOG) {
analog_probes(inner_layout);
return tr("Channels");
}
return NULL;
}
void DeviceOptions::analog_probes(QGridLayout &layout)
{
using namespace Qt;
while(layout.count() > 0)
{
//remove Widgets in QLayoutGrid
QWidget* widget = layout.itemAt(0)->widget();
layout.removeWidget(widget);
delete widget;
}
_probe_widget_list.clear();
_probes_checkBox_list.clear();
_probe_options_binding_list.clear();
QTabWidget *tabWidget = new QTabWidget(this);
tabWidget->setTabPosition(QTabWidget::North);
tabWidget->setUsesScrollButtons(false);
for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) {
sr_channel *const probe = (sr_channel*)l->data;
assert(probe);
QWidget *probe_widget = new QWidget(tabWidget);
QGridLayout *probe_layout = new QGridLayout(probe_widget);
probe_widget->setLayout(probe_layout);
_probe_widget_list.push_back(probe_widget);
QCheckBox *probe_checkBox = new QCheckBox(this);
QVariant vlayout = QVariant::fromValue((void *)probe_layout);
probe_checkBox->setProperty("Layout", vlayout);
probe_checkBox->setProperty("Enable", true);
probe_checkBox->setCheckState(probe->enabled ? Qt::Checked : Qt::Unchecked);
_probes_checkBox_list.push_back(probe_checkBox);
QLabel *en_label = new QLabel(tr("Enable: "), this);
en_label->setProperty("Enable", true);
probe_layout->addWidget(en_label, 0, 0, 1, 1);
probe_layout->addWidget(probe_checkBox, 0, 1, 1, 3);
pv::prop::binding::ProbeOptions *probe_options_binding =
new pv::prop::binding::ProbeOptions(_dev_inst->dev_inst(), probe);
const auto &properties = probe_options_binding->properties();
int i = 1;
for(auto &p : properties)
{
assert(p);
const QString label = p->labeled_widget() ? QString() : p->label();
probe_layout->addWidget(new QLabel(label, probe_widget), i, 0, 1, 1);
QWidget * pow = p->get_widget(probe_widget);
pow->setEnabled(probe_checkBox->isChecked());
if (p->name().contains("Map Default")) {
pow->setProperty("index", probe->index);
connect(pow, SIGNAL(clicked()), this, SLOT(analog_channel_check()));
} else {
if (probe_checkBox->isChecked() && p->name().contains("Map")) {
bool map_default = true;
GVariant* gvar = _dev_inst->get_config(probe, NULL, SR_CONF_PROBE_MAP_DEFAULT);
if (gvar != NULL) {
map_default =g_variant_get_boolean(gvar);
g_variant_unref(gvar);
}
if (map_default)
pow->setEnabled(false);
}
}
probe_layout->addWidget(pow, i, 1, 1, 3);
i++;
}
_probe_options_binding_list.push_back(probe_options_binding);
connect(probe_checkBox, SIGNAL(released()), this, SLOT(channel_enable()));
tabWidget->addTab(probe_widget, QString::fromUtf8(probe->name));
}
layout.addWidget(tabWidget, 0, 0, 1, 1);
}
} // namespace dialogs
} // namespace pv