27 #include <QFileDialog> 30 #include <QMessageBox> 36 #include <boost/algorithm/string/join.hpp> 57 #include <libsigrokcxx/libsigrokcxx.hpp> 59 using std::back_inserter;
63 using std::make_shared;
69 using std::shared_ptr;
73 using sigrok::Capability;
74 using sigrok::ConfigKey;
76 using sigrok::InputFormat;
77 using sigrok::OutputFormat;
79 using boost::algorithm::join;
92 StandardBar(session, parent, view, false),
93 action_new_view_(new QAction(
this)),
94 action_open_(new QAction(
this)),
95 action_save_(new QAction(
this)),
96 action_save_as_(new QAction(
this)),
97 action_save_selection_as_(new QAction(
this)),
98 action_restore_setup_(new QAction(
this)),
99 action_save_setup_(new QAction(
this)),
100 action_connect_(new QAction(
this)),
104 device_selector_(parent, session.device_manager(), action_connect_),
105 configure_button_(
this),
106 configure_button_action_(nullptr),
107 channels_button_(
this),
108 channels_button_action_(nullptr),
109 sample_count_(
" samples",
this),
110 sample_rate_(
"Hz",
this),
111 updating_sample_rate_(false),
112 updating_sample_count_(false),
113 sample_count_supported_(false),
119 setObjectName(QString::fromUtf8(
"MainBar"));
121 setContextMenuPolicy(Qt::PreventContextMenu);
126 QIcon(
":/icons/window-new.png")));
132 QIcon(
":/icons/document-open.png")));
133 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 134 action_open_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_O));
136 action_open_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
146 action_save_->setIcon(QIcon::fromTheme(
"document-save-as",
147 QIcon(
":/icons/document-save-as.png")));
148 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 149 action_save_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
151 action_save_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
158 QIcon(
":/icons/document-save-as.png")));
164 QIcon(
":/icons/document-save-as.png")));
165 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 179 menu_file_export->setTitle(tr(
"&Export"));
180 connect(menu_file_export, SIGNAL(format_selected(shared_ptr<sigrok::OutputFormat>)),
181 this, SLOT(
export_file(shared_ptr<sigrok::OutputFormat>)));
185 menu_file_import->setTitle(tr(
"&Import"));
186 connect(menu_file_import, SIGNAL(format_selected(shared_ptr<sigrok::InputFormat>)),
187 this, SLOT(
import_file(shared_ptr<sigrok::InputFormat>)));
194 QMenu *menu_new_view =
new QMenu();
195 connect(menu_new_view, SIGNAL(triggered(QAction*)),
200 action->setData(QVariant::fromValue(i));
208 vector<QAction*> open_actions;
210 QAction* separator_o =
new QAction(
this);
211 separator_o->setSeparator(
true);
212 open_actions.push_back(separator_o);
217 connect(import_menu, SIGNAL(format_selected(shared_ptr<sigrok::InputFormat>)),
218 this, SLOT(
import_file(shared_ptr<sigrok::InputFormat>)));
222 open_button_->setPopupMode(QToolButton::MenuButtonPopup);
225 vector<QAction*> save_actions;
229 QAction* separator_s =
new QAction(
this);
230 separator_s->setSeparator(
true);
231 save_actions.push_back(separator_s);
236 connect(export_menu, SIGNAL(format_selected(shared_ptr<sigrok::OutputFormat>)),
237 this, SLOT(
export_file(shared_ptr<sigrok::OutputFormat>)));
241 save_button_->setPopupMode(QToolButton::MenuButtonPopup);
249 add_decoder_button_->setIcon(QIcon(
":/icons/add-decoder.svg"));
250 add_decoder_button_->setPopupMode(QToolButton::InstantPopup);
251 add_decoder_button_->setToolTip(tr(
"Add protocol decoder"));
252 add_decoder_button_->setShortcut(QKeySequence(Qt::Key_D));
254 connect(add_decoder_button_, SIGNAL(clicked()),
279 QIcon(
":/icons/preferences-system.png")));
290 connect(&
session_, SIGNAL(capture_state_changed(
int)),
292 connect(&session, SIGNAL(device_changed()),
302 list< shared_ptr<devices::Device> > devs;
304 copy(mgr.
devices().begin(), mgr.
devices().end(), back_inserter(devs));
306 if (std::find(devs.begin(), devs.end(), selected_device) == devs.end())
307 devs.push_back(selected_device);
356 Glib::VariantContainerBase gvar_dict;
358 const uint64_t *elements =
nullptr;
360 map< const ConfigKey*, set<Capability> > keys;
374 const shared_ptr<sigrok::Device> sr_dev = device->device();
377 if (sr_dev->config_check(ConfigKey::EXTERNAL_CLOCK, Capability::GET)) {
379 auto gvar = sr_dev->config_get(ConfigKey::EXTERNAL_CLOCK);
381 bool value = Glib::VariantBase::cast_dynamic<Glib::Variant<bool>>(
385 }
catch (Error& error) {
391 if (sr_dev->config_check(ConfigKey::SAMPLERATE, Capability::LIST)) {
393 gvar_dict = sr_dev->config_list(ConfigKey::SAMPLERATE);
394 }
catch (Error& error) {
395 qDebug() << tr(
"Failed to get sample rate list:") << error.what();
403 if ((gvar_list = g_variant_lookup_value(gvar_dict.gobj(),
404 "samplerate-steps", G_VARIANT_TYPE(
"at")))) {
405 elements = (
const uint64_t *)g_variant_get_fixed_array(
406 gvar_list, &num_elements,
sizeof(uint64_t));
408 const uint64_t
min = elements[0];
409 const uint64_t
max = elements[1];
410 const uint64_t step = elements[2];
412 g_variant_unref(gvar_list);
428 }
else if ((gvar_list = g_variant_lookup_value(gvar_dict.gobj(),
429 "samplerates", G_VARIANT_TYPE(
"at")))) {
430 elements = (
const uint64_t *)g_variant_get_fixed_array(
431 gvar_list, &num_elements,
sizeof(uint64_t));
433 g_variant_unref(gvar_list);
450 auto gvar = device->device()->config_get(ConfigKey::SAMPLERATE);
451 uint64_t samplerate =
452 Glib::VariantBase::cast_dynamic<Glib::Variant<guint64>>(gvar).
get();
457 }
catch (Error& error) {
458 qDebug() << tr(
"Failed to get sample rate:") << error.what();
471 const shared_ptr<sigrok::Device> sr_dev = device->device();
483 uint64_t min_sample_count = 0;
485 bool default_count_set =
false;
487 if (sample_count == 0) {
489 default_count_set =
true;
492 if (sr_dev->config_check(ConfigKey::LIMIT_SAMPLES, Capability::LIST)) {
494 auto gvar = sr_dev->config_list(ConfigKey::LIMIT_SAMPLES);
496 g_variant_get(gvar.gobj(),
"(tt)",
497 &min_sample_count, &max_sample_count);
498 }
catch (Error& error) {
499 qDebug() << tr(
"Failed to get sample limit list:") << error.what();
508 if (sr_dev->config_check(ConfigKey::LIMIT_SAMPLES, Capability::GET)) {
509 auto gvar = sr_dev->config_get(ConfigKey::LIMIT_SAMPLES);
510 sample_count = g_variant_get_uint64(gvar.gobj());
511 if (sample_count == 0) {
513 default_count_set =
true;
524 if (default_count_set)
543 const shared_ptr<sigrok::Device> sr_dev = device->device();
559 if (sr_dev->config_check(ConfigKey::LIMIT_SAMPLES, Capability::SET))
564 connect(&opts->
binding(), SIGNAL(config_changed()),
574 uint64_t sample_rate = 0;
580 const shared_ptr<sigrok::Device> sr_dev = device->device();
585 sr_dev->config_set(ConfigKey::SAMPLERATE,
586 Glib::Variant<guint64>::create(sample_rate));
588 }
catch (Error& error) {
589 qDebug() << tr(
"Failed to configure samplerate:") << error.what();
601 uint64_t sample_count = 0;
607 const shared_ptr<sigrok::Device> sr_dev = device->device();
612 sr_dev->config_set(ConfigKey::LIMIT_SAMPLES,
613 Glib::Variant<guint64>::create(sample_count));
615 }
catch (Error& error) {
616 qDebug() << tr(
"Failed to configure sample count:") << error.what();
629 QMessageBox msg(
this);
630 msg.setText(text +
"\n\n" + info_text);
631 msg.setStandardButtons(QMessageBox::Ok);
632 msg.setIcon(QMessageBox::Warning);
646 pair<uint64_t, uint64_t> sample_range;
649 if (selection_only) {
653 if (!trace_view->
cursors()->enabled()) {
655 "cursors before you can save the data enclosed by them " \
656 "to a session file (e.g. using the Show Cursors button)."));
665 const uint64_t start_sample = (uint64_t)
max(
666 0.0, start_time.convert_to<
double>() * samplerate);
667 const uint64_t end_sample = (uint64_t)
max(
668 0.0, end_time.convert_to<
double>() * samplerate);
670 if ((start_sample == 0) && (end_sample == 0)) {
673 "define a valid range of samples."));
677 sample_range = make_pair(start_sample, end_sample);
679 sample_range = make_pair(0, 0);
683 const vector<string> exts = format->extensions();
684 QString filter = tr(
"%1 files ").arg(
685 QString::fromStdString(format->description()));
690 filter += QString(
"(*.%1);;%2 (*)").arg(
691 QString::fromStdString(join(exts,
", *.")),
695 if (file_name.isEmpty())
696 file_name = QFileDialog::getSaveFileName(
this, tr(
"Save File"), dir, filter);
698 if (file_name.isEmpty())
701 const QString abs_path = QFileInfo(file_name).absolutePath();
705 map<string, Glib::VariantBase>
options;
706 if (!format->options().empty()) {
708 tr(
"Export %1").arg(QString::fromStdString(
709 format->description())),
710 format->options(),
this);
713 options = dlg.options();
716 if (!selection_only) {
724 StoreProgress *dlg =
new StoreProgress(file_name, format, options,
737 const vector<string> exts = format->extensions();
738 const QString filter_exts = exts.empty() ?
"" : QString::fromStdString(
"%1 (%2)").arg(
739 tr(
"%1 files").arg(QString::fromStdString(format->description())),
740 QString::fromStdString(
"*.%1").arg(QString::fromStdString(join(exts,
" *."))));
741 const QString filter_all = QString::fromStdString(
"%1 (%2)").arg(
742 tr(
"All Files"), QString::fromStdString(
"*"));
743 const QString filter = QString::fromStdString(
"%1%2%3").arg(
744 exts.empty() ?
"" : filter_exts,
745 exts.empty() ?
"" :
";;",
749 const QString file_name = QFileDialog::getOpenFileName(
750 this, tr(
"Import File"), dir, filter);
752 if (file_name.isEmpty())
756 map<string, Glib::VariantBase>
options;
757 if (!format->options().empty()) {
759 tr(
"Import %1").arg(QString::fromStdString(
760 format->description())),
761 format->options(),
this);
764 options = dlg.options();
769 const QString abs_path = QFileInfo(file_name).absolutePath();
831 const QString file_name = QFileDialog::getOpenFileName(
832 this, tr(
"Open File"), dir, tr(
833 "sigrok Sessions (*.sr);;" 836 if (!file_name.isEmpty()) {
839 const QString abs_path = QFileInfo(file_name).absolutePath();
854 fi.absoluteFilePath());
872 const QString file_name = QFileDialog::getSaveFileName(
873 this, tr(
"Save File"), dir, tr(
874 "PulseView Session Setups (*.pvs);;" 877 if (file_name.isEmpty())
880 QSettings settings_storage(file_name, QSettings::IniFormat);
889 const QString file_name = QFileDialog::getOpenFileName(
890 this, tr(
"Open File"), dir, tr(
891 "PulseView Session Setups (*.pvs);;" 894 if (file_name.isEmpty())
897 QSettings settings_storage(file_name, QSettings::IniFormat);
923 shared_ptr<data::SignalBase> signal = make_shared<data::MathSignal>(
session_);
935 StandardBar::add_toolbar_widgets();
944 addWidget(add_decoder_button_);
953 (event->type() == QEvent::ToolTip)) {
956 QHelpEvent *help_event =
static_cast<QHelpEvent*
>(event);
958 QString str = tr(
"Total sampling time: %1").arg(
960 QToolTip::showText(help_event->globalPos(), str);
libsigrok allows users to import and export data from files in various formats some of them as generic as others very specific For a list and make sure to check not so common and outright exotic ways to represent data and sigrok tries to suit as many needs as it can To see which formats your version of PulseView just click on the small arrow next to the _Open_ PulseView will ask for the file name to open Once you picked the you may be asked to specify the details of the format
bool sample_count_supported_
void show_session_error(const QString text, const QString info_text)
static const uint64_t MinSampleCount
void select_device(shared_ptr< devices::Device > device)
void commit_sample_count()
void new_view(Session *session, int type)
pv::widgets::SweepTimingWidget sample_rate_
QAction *const action_open_
shared_ptr< CursorPair > cursors() const
QAction *const action_restore_setup_
QAction * action_save() const
QToolButton * new_view_button_
bool updating_sample_rate_
const char * ViewTypeNames[ViewTypeCount]
void add_toolbar_widgets()
bool updating_sample_count_
void restore_setup(QSettings &settings)
QString format_time_si(const Timestamp &v, SIPrefix prefix, unsigned int precision, QString unit, bool sign)
QAction * action_connect() const
QAction * configure_button_action_
QAction * action_save_selection_as() const
void on_actionNewView_triggered(QAction *action=nullptr)
const shared_ptr< sigrok::Context > & context() const
QToolButton * save_button_
const vector< shared_ptr< prop::Property > > & properties()
const list< shared_ptr< devices::HardwareDevice > > & devices() const
void reset_device_selector()
QAction *const action_new_view_
QAction *const action_connect_
T value(details::expression_node< T > *n)
void on_add_math_signal_clicked()
QAction * action_open() const
void on_actionSaveSelectionAs_triggered()
void import_file(shared_ptr< sigrok::InputFormat > format)
void on_device_selected()
QString save_path() const
pv::widgets::PopupToolButton channels_button_
Mac OS X or Android For some we provide binary for others we provide installers and for others we provide AppImage containers that you can run without the need to install anything Check the the usual way to install PulseView is to install the packages provided by your distro s package manager sometimes only outdated packages are made available to you In that you have two options
void commit_sample_rate()
QAction * action_save_as() const
void add_generated_signal(shared_ptr< data::SignalBase > signal)
QAction *const action_save_selection_as_
pv::widgets::SweepTimingWidget sample_count_
static const char * SettingSaveDirectory
T max(const T v0, const T v1)
shared_ptr< devices::Device > device() const
bool eventFilter(QObject *watched, QEvent *event)
double get_samplerate() const
DeviceManager & device_manager()
void set_capture_state(pv::Session::capture_state state)
void set_save_path(QString path)
void update_sample_rate_selector_value()
void on_actionSaveAs_triggered()
void on_actionSave_triggered()
void update_sample_count_selector()
void on_actionConnect_triggered()
void show_decoder_selector(Session *session)
CMake MinSizeRel FORCE endif() add_subdirectory(manual) include(CheckCSourceCompiles) include(CheckCXXCompilerFlag) include(CheckCXXSourceCompiles) include(CMakePushCheckState) include(memaccess) find_package(PkgConfig) if(CMAKE_VERSION VERSION_EQUAL"3.8.0"OR CMAKE_VERSION VERSION_GREATER"3.8.0") check_cxx_compiler_flag("-std
QAction * channels_button_action_
T min(const T v0, const T v1)
void on_capture_state_changed(int state)
shared_ptr< views::ViewBase > main_view() const
void on_actionOpen_triggered()
void set_name(QString name)
void update_device_config_widgets()
void export_file(shared_ptr< sigrok::OutputFormat > format, bool selection_only=false, QString file_name="")
pv::widgets::DeviceToolButton device_selector_
void on_sample_count_changed()
QToolButton * add_math_signal_button_
void on_sample_rate_changed()
manual txt set(MANUAL_OUT_HTML"${CMAKE_CURRENT_BINARY_DIR}/manual.html") set(MANUAL_OUT_PDF"$
it will come up with a session that has the demo device selected That you can get to know the program even when you don t have any hardware to use it you see a list of devices PulseView has recognized If the device you want to use is you can just select it here image::device_selector_dropdown png[] If it s not you ll need to scan for it first Since most serial port and Ethernet devices can t be auto this is usually required for those To do either choose the Connect to Device option from the list or click on the button itself You will see the following you ll need to pick a driver that you want to use In order to do this
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 24 >, boost::multiprecision::et_off > Timestamp
Timestamp type providing yoctosecond resolution.
static const uint64_t MaxSampleCount
QAction *const action_save_as_
MainBar(Session &session, QWidget *parent, pv::views::trace::View *view)
pv::widgets::PopupToolButton configure_button_
static const char * SettingOpenDirectory
QToolButton * open_button_
void update_sample_rate_selector()
QAction *const action_save_setup_
QAction *const action_save_
void update_device_list()
static const uint64_t DefaultSampleCount
void on_actionSaveSetup_triggered()
void on_actionRestoreSetup_triggered()
void on_add_decoder_clicked()
void load_file(QString file_name, QString setup_file_name=QString(), shared_ptr< sigrok::InputFormat > format=nullptr, const map< string, Glib::VariantBase > &options=map< string, Glib::VariantBase >())
void save_setup(QSettings &settings) const