pv/devicemanager.cpp
pv/mainwindow.cpp
pv/sigsession.cpp
+ pv/storesession.cpp
pv/data/analog.cpp
pv/data/analogsnapshot.cpp
pv/data/logic.cpp
pv/data/snapshot.cpp
pv/dialogs/about.cpp
pv/dialogs/connect.cpp
+ pv/dialogs/storeprogress.cpp
pv/popups/deviceoptions.cpp
pv/popups/probes.cpp
pv/prop/bool.cpp
set(pulseview_HEADERS
pv/mainwindow.h
pv/sigsession.h
+ pv/storesession.h
pv/dialogs/about.h
pv/dialogs/connect.h
+ pv/dialogs/storeprogress.h
pv/popups/probes.h
pv/popups/deviceoptions.h
pv/prop/bool.h
<file>icons/configure.png</file>
<file>icons/decoder-delete.svg</file>
<file>icons/document-open.png</file>
+ <file>icons/document-save-as.png</file>
<file>icons/probes.svg</file>
<file>icons/sigrok-logo-notext.png</file>
<file>icons/status-green.svg</file>
{
assert(data);
assert(start_sample >= 0);
- assert(start_sample < (int64_t)_sample_count);
+ assert(start_sample <= (int64_t)_sample_count);
assert(end_sample >= 0);
- assert(end_sample < (int64_t)_sample_count);
+ assert(end_sample <= (int64_t)_sample_count);
assert(start_sample <= end_sample);
lock_guard<recursive_mutex> lock(_mutex);
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2014 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 "storeprogress.h"
+
+namespace pv {
+namespace dialogs {
+
+StoreProgress::StoreProgress(const QString &file_name,
+ const SigSession &session, QWidget *parent) :
+ QProgressDialog(tr("Saving..."), tr("Cancel"), 0, 0, parent),
+ _session(file_name.toStdString(), session)
+{
+ connect(&_session, SIGNAL(progress_updated()),
+ this, SLOT(on_progress_updated()));
+}
+
+StoreProgress::~StoreProgress()
+{
+ _session.wait();
+}
+
+void StoreProgress::run()
+{
+ if (_session.start())
+ show();
+ else
+ show_error();
+}
+
+void StoreProgress::show_error()
+{
+ QMessageBox msg(parentWidget());
+ msg.setText(tr("Failed to save session."));
+ msg.setInformativeText(_session.error());
+ msg.setStandardButtons(QMessageBox::Ok);
+ msg.setIcon(QMessageBox::Warning);
+ msg.exec();
+}
+
+void StoreProgress::closeEvent(QCloseEvent*)
+{
+ _session.cancel();
+}
+
+void StoreProgress::on_progress_updated()
+{
+ const std::pair<uint64_t, uint64_t> p = _session.progress();
+ assert(p.first <= p.second);
+
+ setValue(p.first);
+ setMaximum(p.second);
+
+ const QString err = _session.error();
+ if (!err.isEmpty()) {
+ show_error();
+ close();
+ }
+
+ if (p.first == p.second)
+ close();
+}
+
+} // dialogs
+} // pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2014 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 PULSEVIEW_PV_DIALOGS_SAVEPROGRESS_H
+#define PULSEVIEW_PV_DIALOGS_SAVEPROGRESS_H
+
+#include <set>
+
+#include <boost/shared_ptr.hpp>
+
+#include <QProgressDialog>
+
+#include <pv/storesession.h>
+
+namespace pv {
+
+class SigSession;
+
+namespace dialogs {
+
+class StoreProgress : public QProgressDialog
+{
+ Q_OBJECT
+
+public:
+ StoreProgress(const QString &file_name, const SigSession &session,
+ QWidget *parent = 0);
+
+ virtual ~StoreProgress();
+
+ void run();
+
+private:
+ void show_error();
+
+ void closeEvent(QCloseEvent*);
+
+private slots:
+ void on_progress_updated();
+
+private:
+ pv::StoreSession _session;
+};
+
+} // dialogs
+} // pv
+
+#endif // PULSEVIEW_PV_DIALOGS_SAVEPROGRESS_H
#include "devicemanager.h"
#include "dialogs/about.h"
#include "dialogs/connect.h"
+#include "dialogs/storeprogress.h"
#include "toolbars/samplingbar.h"
#include "view/logicsignal.h"
#include "view/view.h"
action_open->setObjectName(QString::fromUtf8("actionOpen"));
menu_file->addAction(action_open);
+ QAction *const action_save_as = new QAction(this);
+ action_save_as->setText(QApplication::translate(
+ "MainWindow", "&Save As...", 0, QApplication::UnicodeUTF8));
+ action_save_as->setIcon(QIcon::fromTheme("document-save-as",
+ QIcon(":/icons/document-save-as.png")));
+ action_save_as->setObjectName(QString::fromUtf8("actionSaveAs"));
+ menu_file->addAction(action_save_as);
+
menu_file->addSeparator();
QAction *const action_connect = new QAction(this);
load_file(file_name);
}
+void MainWindow::on_actionSaveAs_triggered()
+{
+ using pv::dialogs::StoreProgress;
+
+ // Stop any currently running capture session
+ _session.stop_capture();
+
+ // Show the dialog
+ const QString file_name = QFileDialog::getSaveFileName(
+ this, tr("Save File"), "", tr("Sigrok Sessions (*.sr)"));
+
+ if (file_name.isEmpty())
+ return;
+
+ StoreProgress *dlg = new StoreProgress(file_name, _session, this);
+ dlg->run();
+}
+
void MainWindow::on_actionConnect_triggered()
{
// Stop any currently running capture session
const QString text, const QString info_text);
void on_actionOpen_triggered();
+ void on_actionSaveAs_triggered();
void on_actionQuit_triggered();
void on_actionConnect_triggered();
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2014 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 "storesession.h"
+
+#include <pv/sigsession.h>
+#include <pv/data/logic.h>
+#include <pv/data/logicsnapshot.h>
+#include <pv/view/signal.h>
+
+using boost::dynamic_pointer_cast;
+using boost::mutex;
+using boost::shared_ptr;
+using boost::thread;
+using boost::lock_guard;
+using std::deque;
+using std::make_pair;
+using std::min;
+using std::pair;
+using std::set;
+using std::string;
+using std::vector;
+
+namespace pv {
+
+const size_t StoreSession::BlockSize = 1024 * 1024;
+
+StoreSession::StoreSession(const std::string &file_name,
+ const SigSession &session) :
+ _file_name(file_name),
+ _session(session),
+ _units_stored(0),
+ _unit_count(0)
+{
+}
+
+StoreSession::~StoreSession()
+{
+ wait();
+}
+
+pair<uint64_t, uint64_t> StoreSession::progress() const
+{
+ lock_guard<mutex> lock(_mutex);
+ return make_pair(_units_stored, _unit_count);
+}
+
+const QString& StoreSession::error() const
+{
+ lock_guard<mutex> lock(_mutex);
+ return _error;
+}
+
+bool StoreSession::start()
+{
+ set< shared_ptr<data::SignalData> > data_set =
+ _session.get_data();
+ const vector< shared_ptr<view::Signal> > sigs =
+ _session.get_signals();
+
+ // Check we have logic data
+ if (data_set.empty() || sigs.empty()) {
+ _error = tr("No data to save.");
+ return false;
+ }
+
+ if (data_set.size() > 1) {
+ _error = tr("PulseView currently only has support for "
+ "storing a single data stream.");
+ return false;
+ }
+
+ // Get the logic data
+ //shared_ptr<data::SignalData
+ shared_ptr<data::Logic> data;
+ if (!(data = dynamic_pointer_cast<data::Logic>(*data_set.begin()))) {
+ _error = tr("PulseView currently only has support for "
+ "storing a logic data.");
+ return false;
+ }
+
+ // Get the snapshot
+ const deque< shared_ptr<data::LogicSnapshot> > &snapshots =
+ data->get_snapshots();
+
+ if (snapshots.empty()) {
+ _error = tr("No snapshots to save.");
+ return false;
+ }
+
+ const shared_ptr<data::LogicSnapshot> snapshot(snapshots.front());
+ assert(snapshot);
+
+ // Make a list of probes
+ char **const probes = new char*[sigs.size() + 1];
+ for (size_t i = 0; i < sigs.size(); i++) {
+ shared_ptr<view::Signal> sig(sigs[i]);
+ assert(sig);
+ probes[i] = strdup(sig->get_name().toUtf8().constData());
+ }
+ probes[sigs.size()] = NULL;
+
+ // Begin storing
+ if (sr_session_save_init(_file_name.c_str(),
+ data->samplerate(), probes) != SR_OK) {
+ _error = tr("Error while saving.");
+ return false;
+ }
+
+ // Delete the probes array
+ for (size_t i = 0; i <= sigs.size(); i++)
+ free(probes[i]);
+ delete[] probes;
+
+ _thread = boost::thread(&StoreSession::store_proc, this, snapshot);
+ return true;
+}
+
+void StoreSession::wait()
+{
+ _thread.join();
+}
+
+void StoreSession::cancel()
+{
+ _thread.interrupt();
+}
+
+void StoreSession::store_proc(shared_ptr<data::LogicSnapshot> snapshot)
+{
+ assert(snapshot);
+
+ uint64_t start_sample = 0;
+
+ /// TODO: Wrap this in a std::unique_ptr when we transition to C++11
+ uint8_t *const data = new uint8_t[BlockSize];
+ assert(data);
+
+ const int unit_size = snapshot->unit_size();
+ assert(unit_size != 0);
+
+ {
+ lock_guard<mutex> lock(_mutex);
+ _unit_count = snapshot->get_sample_count();
+ }
+
+ const unsigned int samples_per_block = BlockSize / unit_size;
+
+ while (!boost::this_thread::interruption_requested() &&
+ start_sample < _unit_count)
+ {
+ progress_updated();
+
+ const uint64_t end_sample = min(
+ start_sample + samples_per_block, _unit_count);
+ snapshot->get_samples(data, start_sample, end_sample);
+
+ if(sr_session_append(_file_name.c_str(), data, unit_size,
+ end_sample - start_sample) != SR_OK)
+ {
+ _error = tr("Error while saving.");
+ break;
+ }
+
+ start_sample = end_sample;
+
+ {
+ lock_guard<mutex> lock(_mutex);
+ _units_stored = start_sample;
+ }
+ }
+
+ progress_updated();
+
+ delete[] data;
+}
+
+} // pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2014 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 PULSEVIEW_PV_STORESESSION_H
+#define PULSEVIEW_PV_STORESESSION_H
+
+#include <stdint.h>
+
+#include <string>
+
+#include <boost/thread.hpp>
+
+#include <QObject>
+
+namespace pv {
+
+class SigSession;
+
+namespace data {
+class LogicSnapshot;
+}
+
+class StoreSession : public QObject
+{
+ Q_OBJECT
+
+private:
+ static const size_t BlockSize;
+
+public:
+ StoreSession(const std::string &file_name,
+ const SigSession &session);
+
+ ~StoreSession();
+
+ std::pair<uint64_t, uint64_t> progress() const;
+
+ const QString& error() const;
+
+ bool start();
+
+ void wait();
+
+ void cancel();
+
+private:
+ void store_proc(boost::shared_ptr<pv::data::LogicSnapshot> snapshot);
+
+signals:
+ void progress_updated();
+
+private:
+ const std::string _file_name;
+ const SigSession &_session;
+
+ boost::thread _thread;
+
+ mutable boost::mutex _mutex;
+ uint64_t _units_stored;
+ uint64_t _unit_count;
+ QString _error;
+};
+
+} // pv
+
+#endif // PULSEVIEW_PV_STORESESSION_H