]> sigrok.org Git - pulseview.git/blobdiff - pv/session.cpp
Session: Fix issue #67 by improving error handling
[pulseview.git] / pv / session.cpp
index 840773d1aa7115bd4dcc7594496c776231bcdd15..b4ecc6a87c2f4886c3a812df1191cea08542e4f8 100644 (file)
@@ -25,6 +25,7 @@
 #include <sys/stat.h>
 
 #include <QDebug>
+#include <QDir>
 #include <QFileInfo>
 
 #include "devicemanager.hpp"
@@ -37,6 +38,7 @@
 #include "data/decode/decoder.hpp"
 #include "data/logic.hpp"
 #include "data/logicsegment.hpp"
+#include "data/mathsignal.hpp"
 #include "data/signalbase.hpp"
 
 #include "devices/hardwaredevice.hpp"
@@ -124,6 +126,8 @@ Session::Session(DeviceManager &device_manager, QString name) :
        cur_samplerate_(0),
        data_saved_(true)
 {
+       // Use this name also for the QObject instance
+       setObjectName(name_);
 }
 
 Session::~Session()
@@ -173,18 +177,20 @@ void Session::set_name(QString name)
 
        name_ = name;
 
+       // Use this name also for the QObject instance
+       setObjectName(name_);
+
        name_changed();
 }
 
-QString Session::path() const
+QString Session::save_path() const
 {
-       return path_;
+       return save_path_;
 }
 
-void Session::set_path(QString path)
+void Session::set_save_path(QString path)
 {
-       path_ = path;
-       set_name(QFileInfo(path).fileName());
+       save_path_ = path;
 }
 
 const vector< shared_ptr<views::ViewBase> > Session::views() const
@@ -214,25 +220,33 @@ bool Session::data_saved() const
 
 void Session::save_setup(QSettings &settings) const
 {
-       int i = 0;
+       int i;
+       int decode_signal_count = 0;
+       int gen_signal_count = 0;
 
        // Save channels and decoders
        for (const shared_ptr<data::SignalBase>& base : signalbases_) {
 #ifdef ENABLE_DECODE
                if (base->is_decode_signal()) {
-                       settings.beginGroup("decode_signal" + QString::number(i++));
+                       settings.beginGroup("decode_signal" + QString::number(decode_signal_count++));
                        base->save_settings(settings);
                        settings.endGroup();
                } else
 #endif
-               {
+               if (base->is_generated()) {
+                       settings.beginGroup("generated_signal" + QString::number(gen_signal_count++));
+                       settings.setValue("type", base->type());
+                       base->save_settings(settings);
+                       settings.endGroup();
+               } else {
                        settings.beginGroup(base->internal_name());
                        base->save_settings(settings);
                        settings.endGroup();
                }
        }
 
-       settings.setValue("decode_signals", i);
+       settings.setValue("decode_signals", decode_signal_count);
+       settings.setValue("generated_signals", gen_signal_count);
 
        // Save view states and their signal settings
        // Note: main_view must be saved as view0
@@ -323,25 +337,36 @@ void Session::save_settings(QSettings &settings) const
                        settings.endGroup();
                }
 
-               shared_ptr<devices::SessionFile> sessionfile_device =
-                       dynamic_pointer_cast<devices::SessionFile>(device_);
-
-               if (sessionfile_device) {
+               // Having saved the data to srzip overrides the current device. This is
+               // a crappy hack around the fact that saving e.g. an imported file to
+               // srzip would require changing the underlying libsigrok device
+               if (!save_path_.isEmpty()) {
+                       QFileInfo fi = QFileInfo(QDir(save_path_), name_);
                        settings.setValue("device_type", "sessionfile");
                        settings.beginGroup("device");
-                       settings.setValue("filename", QString::fromStdString(
-                               sessionfile_device->full_name()));
+                       settings.setValue("filename", fi.absoluteFilePath());
                        settings.endGroup();
-               }
+               } else {
+                       shared_ptr<devices::SessionFile> sessionfile_device =
+                               dynamic_pointer_cast<devices::SessionFile>(device_);
+
+                       if (sessionfile_device) {
+                               settings.setValue("device_type", "sessionfile");
+                               settings.beginGroup("device");
+                               settings.setValue("filename", QString::fromStdString(
+                                       sessionfile_device->full_name()));
+                               settings.endGroup();
+                       }
 
-               shared_ptr<devices::InputFile> inputfile_device =
-                       dynamic_pointer_cast<devices::InputFile>(device_);
+                       shared_ptr<devices::InputFile> inputfile_device =
+                               dynamic_pointer_cast<devices::InputFile>(device_);
 
-               if (inputfile_device) {
-                       settings.setValue("device_type", "inputfile");
-                       settings.beginGroup("device");
-                       inputfile_device->save_meta_to_settings(settings);
-                       settings.endGroup();
+                       if (inputfile_device) {
+                               settings.setValue("device_type", "inputfile");
+                               settings.beginGroup("device");
+                               inputfile_device->save_meta_to_settings(settings);
+                               settings.endGroup();
+                       }
                }
 
                save_setup(settings);
@@ -357,11 +382,34 @@ void Session::restore_setup(QSettings &settings)
                settings.endGroup();
        }
 
+       // Restore generated signals
+       int gen_signal_count = settings.value("generated_signals").toInt();
+
+       for (int i = 0; i < gen_signal_count; i++) {
+               settings.beginGroup("generated_signal" + QString::number(i));
+               SignalBase::ChannelType type = (SignalBase::ChannelType)settings.value("type").toInt();
+               shared_ptr<data::SignalBase> signal;
+
+               if (type == SignalBase::MathChannel)
+                       signal = make_shared<data::MathSignal>(*this);
+               else
+                       qWarning() << tr("Can't restore generated signal of unknown type %1 (%2)") \
+                               .arg((int)type) \
+                               .arg(settings.value("name").toString());
+
+               if (signal) {
+                       add_generated_signal(signal);
+                       signal->restore_settings(settings);
+               }
+
+               settings.endGroup();
+       }
+
        // Restore decoders
 #ifdef ENABLE_DECODE
-       int decode_signals = settings.value("decode_signals").toInt();
+       int decode_signal_count = settings.value("decode_signals").toInt();
 
-       for (int i = 0; i < decode_signals; i++) {
+       for (int i = 0; i < decode_signal_count; i++) {
                settings.beginGroup("decode_signal" + QString::number(i));
                shared_ptr<data::DecodeSignal> signal = add_decode_signal();
                signal->restore_settings(settings);
@@ -453,21 +501,21 @@ void Session::restore_settings(QSettings &settings)
                        set_device(device);
 
                settings.endGroup();
-       }
 
+               if (device)
+                       restore_setup(settings);
+       }
 
-       QString path;
+       QString filename;
        if ((device_type == "sessionfile") || (device_type == "inputfile")) {
                if (device_type == "sessionfile") {
                        settings.beginGroup("device");
-                       const QString filename = settings.value("filename").toString();
+                       filename = settings.value("filename").toString();
                        settings.endGroup();
 
-                       if (QFileInfo(filename).isReadable()) {
-                       path = filename;
+                       if (QFileInfo(filename).isReadable())
                                device = make_shared<devices::SessionFile>(device_manager_.context(),
                                        filename.toStdString());
-                       }
                }
 
                if (device_type == "inputfile") {
@@ -477,8 +525,10 @@ void Session::restore_settings(QSettings &settings)
                        settings.endGroup();
                }
 
+
                if (device) {
                        set_device(device);
+                       restore_setup(settings);
 
                        start_capture([](QString infoMessage) {
                                // TODO Emulate noquote()
@@ -487,13 +537,15 @@ void Session::restore_settings(QSettings &settings)
                        set_name(QString::fromStdString(
                                dynamic_pointer_cast<devices::File>(device)->display_name(device_manager_)));
 
-                       if (!path.isEmpty())
-                               set_path(path);
+                       if (!filename.isEmpty()) {
+                               // Only set the save path if we load an srzip file
+                               if (device_type == "sessionfile")
+                                       set_save_path(QFileInfo(filename).absolutePath());
+
+                               set_name(QFileInfo(filename).fileName());
+                       }
                }
        }
-
-       if (device)
-               restore_setup(settings);
 }
 
 void Session::select_device(shared_ptr<devices::Device> device)
@@ -562,6 +614,9 @@ void Session::set_device(shared_ptr<devices::Device> device)
        } catch (const QString &e) {
                device_.reset();
                MainWindow::show_session_error(tr("Failed to open device"), e);
+       } catch (const sigrok::Error &e) {
+               device_.reset();
+               MainWindow::show_session_error(tr("Failed to open device"), QString(e.what()));
        }
 
        if (device_) {
@@ -704,8 +759,11 @@ void Session::load_file(QString file_name, QString setup_file_name,
                                        file_name.toStdString())));
        } catch (Error& e) {
                MainWindow::show_session_error(tr("Failed to load %1").arg(file_name), e.what());
-               set_default_device();
-               main_bar_->update_device_list();
+               return;
+       }
+
+       if (!device_) {
+               MainWindow::show_session_error(errorMessage, "");
                return;
        }
 
@@ -724,9 +782,13 @@ void Session::load_file(QString file_name, QString setup_file_name,
        main_bar_->update_device_list();
 
        start_capture([&, errorMessage](QString infoMessage) {
-               MainWindow::show_session_error(errorMessage, infoMessage); });
+               Q_EMIT session_error_raised(errorMessage, infoMessage); });
 
-       set_path(file_name);
+       // Only set save path if we loaded an srzip file
+       if (dynamic_pointer_cast<devices::SessionFile>(device_))
+               set_save_path(QFileInfo(file_name).absolutePath());
+
+       set_name(QFileInfo(file_name).fileName());
 }
 
 Session::capture_state Session::get_capture_state() const
@@ -761,6 +823,7 @@ void Session::start_capture(function<void (const QString)> error_handler)
                d->clear();
 
        trigger_list_.clear();
+       segment_sample_count_.clear();
 
        // Revert name back to default name (e.g. "Session 1") for real devices
        // as the (possibly saved) data is gone. File devices keep their name.
@@ -772,9 +835,10 @@ void Session::start_capture(function<void (const QString)> error_handler)
                name_changed();
        }
 
+       acq_start_time_ = Glib::DateTime::create_now_local();
+
        // Begin the session
-       sampling_thread_ = std::thread(
-               &Session::sample_thread_proc, this, error_handler);
+       sampling_thread_ = std::thread(&Session::sample_thread_proc, this, error_handler);
 }
 
 void Session::stop_capture()
@@ -867,16 +931,22 @@ double Session::get_samplerate() const
        return samplerate;
 }
 
-uint32_t Session::get_segment_count() const
+Glib::DateTime Session::get_acquisition_start_time() const
 {
-       uint32_t value = 0;
+       return acq_start_time_;
+}
 
-       // Find the highest number of segments
-       for (const shared_ptr<data::SignalData>& data : all_signal_data_)
-               if (data->get_segment_count() > value)
-                       value = data->get_segment_count();
+uint32_t Session::get_highest_segment_id() const
+{
+       return highest_segment_id_;
+}
 
-       return value;
+uint64_t Session::get_segment_sample_count(uint32_t segment_id) const
+{
+       if (segment_id < segment_sample_count_.size())
+               return segment_sample_count_[segment_id];
+       else
+               return 0;
 }
 
 vector<util::Timestamp> Session::get_triggers(uint32_t segment_id) const
@@ -895,6 +965,18 @@ const vector< shared_ptr<data::SignalBase> > Session::signalbases() const
        return signalbases_;
 }
 
+uint32_t Session::get_signal_count(data::SignalBase::ChannelType type) const
+{
+       return count_if(signalbases_.begin(), signalbases_.end(),
+               [&] (shared_ptr<SignalBase> sb) { return sb->type() == type; });
+}
+
+uint32_t Session::get_next_signal_index(data::SignalBase::ChannelType type)
+{
+       next_index_list_[type]++;
+       return next_index_list_[type];
+}
+
 void Session::add_generated_signal(shared_ptr<data::SignalBase> signal)
 {
        signalbases_.push_back(signal);
@@ -978,7 +1060,8 @@ MetadataObjManager* Session::metadata_obj_manager()
 
 void Session::set_capture_state(capture_state state)
 {
-       bool changed;
+       if (state == capture_state_)
+               return;
 
        if (state == Running)
                acq_time_.restart();
@@ -987,12 +1070,10 @@ void Session::set_capture_state(capture_state state)
 
        {
                lock_guard<mutex> lock(sampling_mutex_);
-               changed = capture_state_ != state;
                capture_state_ = state;
        }
 
-       if (changed)
-               capture_state_changed(state);
+       capture_state_changed(state);
 }
 
 void Session::update_signals()
@@ -1279,6 +1360,7 @@ void Session::signal_new_segment()
 
        if (new_segment_id > highest_segment_id_) {
                highest_segment_id_ = new_segment_id;
+               segment_sample_count_.emplace_back(0);
                new_segment(highest_segment_id_);
        }
 }
@@ -1479,6 +1561,9 @@ void Session::feed_in_logic(shared_ptr<sigrok::Logic> logic)
 
        cur_logic_segment_->append_payload(logic);
 
+       segment_sample_count_[highest_segment_id_] =
+               max(segment_sample_count_[highest_segment_id_], cur_logic_segment_->get_sample_count());
+
        data_received();
 }
 
@@ -1545,6 +1630,9 @@ void Session::feed_in_analog(shared_ptr<sigrok::Analog> analog)
                // Append the samples in the segment
                segment->append_interleaved_samples(channel_data++, analog->num_samples(),
                        channels.size());
+
+               segment_sample_count_[highest_segment_id_] =
+                       max(segment_sample_count_[highest_segment_id_], segment->get_sample_count());
        }
 
        if (sweep_beginning) {