]> sigrok.org Git - pulseview.git/commitdiff
Added DeviceManager
authorJoel Holdsworth <redacted>
Sat, 27 Apr 2013 20:53:21 +0000 (21:53 +0100)
committerJoel Holdsworth <redacted>
Sat, 27 Apr 2013 21:00:32 +0000 (22:00 +0100)
This class now manages the application device list, scanning for
devices, and releasing them when they are no longer needed.

This fixes bug #108.

CMakeLists.txt
main.cpp
pv/devicemanager.cpp [new file with mode: 0644]
pv/devicemanager.h [new file with mode: 0644]
pv/dialogs/connect.cpp
pv/dialogs/connect.h
pv/mainwindow.cpp
pv/mainwindow.h

index d673cf81da6cd4b3d022b52eda8d5628edfeb353..226cd36381c7e45253fb132acfd41afc576693f9 100644 (file)
@@ -100,6 +100,7 @@ configure_file (
 
 set(pulseview_SOURCES
        main.cpp
+       pv/devicemanager.cpp
        pv/mainwindow.cpp
        pv/sigsession.cpp
        pv/data/analog.cpp
index 715dc526c2f07fce90eb9d111cf253acf57dc09a..1761df6e77190bef639c0c527d24e891fb7fb417 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -34,6 +34,7 @@
 #include "signalhandler.h"
 #endif
 
+#include "pv/devicemanager.h"
 #include "pv/mainwindow.h"
 
 #include "config.h"
@@ -128,20 +129,12 @@ int main(int argc, char *argv[])
                srd_decoder_load_all();
 #endif
 
-               // Initialize all libsigrok drivers
-               sr_dev_driver **const drivers = sr_driver_list();
-               for (sr_dev_driver **driver = drivers; *driver; driver++) {
-                       if (sr_driver_init(sr_ctx, *driver) != SR_OK) {
-                               qDebug("Failed to initialize driver %s",
-                                       (*driver)->name);
-                               ret = 1;
-                               break;
-                       }
-               }
+               try {
+                       // Create the device manager, initialise the drivers
+                       pv::DeviceManager device_manager(sr_ctx);
 
-               if (ret == 0) {
                        // Initialise the main window
-                       pv::MainWindow w(open_file);
+                       pv::MainWindow w(device_manager, open_file);
                        w.show();
 
 #ifdef ENABLE_SIGNALS
@@ -162,6 +155,9 @@ int main(int argc, char *argv[])
 
                        // Run the application
                        ret = a.exec();
+
+               } catch(std::exception e) {
+                       qDebug() << e.what();
                }
 
 #ifdef ENABLE_SIGROKDECODE
diff --git a/pv/devicemanager.cpp b/pv/devicemanager.cpp
new file mode 100644 (file)
index 0000000..4018c04
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2013 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 "devicemanager.h"
+
+#include <cassert>
+#include <cstring>
+#include <stdexcept>
+#include <string>
+
+#include <libsigrok/libsigrok.h>
+
+using namespace std;
+
+namespace pv {
+
+DeviceManager::DeviceManager(struct sr_context *sr_ctx) :
+       _sr_ctx(sr_ctx)
+{
+       init_drivers();
+       scan_all_drivers();
+}
+
+DeviceManager::~DeviceManager()
+{
+       release_devices();
+}
+
+const std::list<sr_dev_inst*>& DeviceManager::devices() const
+{
+       return _devices;
+}
+
+list<sr_dev_inst*> DeviceManager::driver_scan(
+       struct sr_dev_driver *const driver, GSList *const drvopts)
+{
+       list<sr_dev_inst*> driver_devices;
+
+       assert(driver);
+
+       // Remove any device instances from this driver from the device
+       // list. They will not be valid after the scan.
+       list<sr_dev_inst*>::iterator i = _devices.begin();
+       while (i != _devices.end()) {
+               if ((*i)->driver == driver)
+                       i = _devices.erase(i);
+               else
+                       i++;
+       }
+
+       // Clear all the old device instances from this driver
+       sr_dev_clear(driver);
+
+       // Do the scan
+       GSList *const devices = sr_driver_scan(driver, drvopts);
+       for (GSList *l = devices; l; l = l->next)
+               driver_devices.push_back((sr_dev_inst*)l->data);
+       g_slist_free(devices);
+       driver_devices.sort(compare_devices);
+
+       // Add the scanned devices to the main list
+       _devices.insert(_devices.end(), driver_devices.begin(),
+               driver_devices.end());
+       _devices.sort(compare_devices);
+
+       return driver_devices;
+}
+
+void DeviceManager::init_drivers()
+{
+       // Initialise all libsigrok drivers
+       sr_dev_driver **const drivers = sr_driver_list();
+       for (sr_dev_driver **driver = drivers; *driver; driver++) {
+               if (sr_driver_init(_sr_ctx, *driver) != SR_OK) {
+                       throw runtime_error(
+                               string("Failed to initialize driver ") +
+                               string((*driver)->name));
+               }
+       }
+}
+
+void DeviceManager::release_devices()
+{
+       sr_dev_driver **const drivers = sr_driver_list();
+       for (sr_dev_driver **driver = drivers; *driver; driver++)
+               sr_dev_clear(*driver);
+}
+
+void DeviceManager::scan_all_drivers()
+{
+       // Scan all drivers for all devices.
+       struct sr_dev_driver **const drivers = sr_driver_list();
+       for (struct sr_dev_driver **driver = drivers; *driver; driver++)
+               driver_scan(*driver);
+}
+
+bool DeviceManager::compare_devices(const sr_dev_inst *const a,
+       const sr_dev_inst *const b)
+{
+       assert(a);
+       assert(b);
+
+       const int vendor_cmp = strcasecmp(a->vendor, b->vendor);
+       if(vendor_cmp < 0)
+               return true;
+       else if(vendor_cmp > 0)
+               return false;
+
+       const int model_cmp = strcasecmp(a->model, b->model);
+       if(model_cmp < 0)
+               return true;
+       else if(model_cmp > 0)
+               return false;
+
+       return strcasecmp(a->version, b->version) < 0;
+}
+
+} // namespace pv
diff --git a/pv/devicemanager.h b/pv/devicemanager.h
new file mode 100644 (file)
index 0000000..070c3cc
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2013 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_DEVICEMANAGER_H
+#define PULSEVIEW_PV_DEVICEMANAGER_H
+
+#include <glib.h>
+
+#include <list>
+
+struct sr_context;
+struct sr_dev_driver;
+struct sr_dev_inst;
+
+namespace pv {
+
+class DeviceManager
+{
+public:
+       DeviceManager(struct sr_context *sr_ctx);
+
+       ~DeviceManager();
+
+       const std::list<sr_dev_inst*>& devices() const;
+
+       std::list<sr_dev_inst*> driver_scan(
+               struct sr_dev_driver *const driver,
+               GSList *const drvopts = NULL);
+
+private:
+       void init_drivers();
+
+       static void release_devices();
+
+       void scan_all_drivers();
+
+       static bool compare_devices(const sr_dev_inst *const a,
+               const sr_dev_inst *const b);
+
+private:
+       struct sr_context *const _sr_ctx;
+       std::list<sr_dev_inst*> _devices;
+};
+
+} // namespace pv
+
+#endif // PULSEVIEW_PV_DEVICEMANAGER_H
index 02941f2f6785e02efcff07a80a6520c16d8e36d2..eefd41b7db3e3af982e619c46062ade3523b3e8b 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
+#include <boost/foreach.hpp>
+
 #include "connect.h"
 
+#include "pv/devicemanager.h"
+
 extern "C" {
 /* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */
 #define __STDC_FORMAT_MACROS
@@ -27,13 +31,16 @@ extern "C" {
 #include <libsigrok/libsigrok.h>
 }
 
+using namespace std;
+
 extern sr_context *sr_ctx;
 
 namespace pv {
 namespace dialogs {
 
-Connect::Connect(QWidget *parent) :
+Connect::Connect(QWidget *parent, pv::DeviceManager &device_manager) :
        QDialog(parent),
+       _device_manager(device_manager),
        _layout(this),
        _form(this),
        _form_layout(&_form),
@@ -148,11 +155,12 @@ void Connect::scan_pressed()
                drvopts = g_slist_append(drvopts, src);
        }
 
-       GSList *const devices = sr_driver_scan(driver, drvopts);
+       const list<sr_dev_inst*> devices = _device_manager.driver_scan(
+               driver, drvopts);
 
-       for (GSList *l = devices; l; l = l->next) {
+       g_slist_free_full(drvopts, (GDestroyNotify)free_drvopts);
 
-               sr_dev_inst *const sdi = (sr_dev_inst*)l->data;
+       BOOST_FOREACH(sr_dev_inst *const sdi, devices) {
 
                QString text;
                if (sdi->vendor && sdi->vendor[0])
@@ -172,9 +180,6 @@ void Connect::scan_pressed()
                _device_list.addItem(item);
        }
 
-       g_slist_free(devices);
-       g_slist_free_full(drvopts, (GDestroyNotify)free_drvopts);
-
        _device_list.setCurrentRow(0);
        _button_box.button(QDialogButtonBox::Ok)->setDisabled(false);
 }
index eeb108c105dd5a4c28edaf4e658ed10fa2e137f6..257efd359b860da1f721dc9a9c9aba0454d40750 100644 (file)
@@ -34,6 +34,9 @@ struct sr_config;
 struct sr_dev_inst;
 
 namespace pv {
+
+class DeviceManager;
+
 namespace dialogs {
 
 class Connect : public QDialog
@@ -41,7 +44,7 @@ class Connect : public QDialog
        Q_OBJECT
 
 public:
-       Connect(QWidget *parent);
+       Connect(QWidget *parent, pv::DeviceManager &device_manager);
 
        struct sr_dev_inst* get_selected_device() const;
 
@@ -61,6 +64,8 @@ private:
        static void free_drvopts(sr_config *src);
 
 private:
+       pv::DeviceManager &_device_manager;
+
        QVBoxLayout _layout;
 
        QWidget _form;
index bd2f5fea99a112fcfa94e848b39cbe5e12d5a73a..16147b14ff6df87f0960a7783c8c07c928efe130 100644 (file)
@@ -23,6 +23,7 @@
 #endif
 
 #include <boost/bind.hpp>
+#include <boost/foreach.hpp>
 
 #include <QAction>
 #include <QApplication>
@@ -36,6 +37,8 @@
 #include <QWidget>
 
 #include "mainwindow.h"
+
+#include "devicemanager.h"
 #include "dialogs/about.h"
 #include "dialogs/connect.h"
 #include "toolbars/samplingbar.h"
 #include <glib.h>
 #include <libsigrok/libsigrok.h>
 
+using namespace std;
 
 namespace pv {
 
-MainWindow::MainWindow(const char *open_file_name,
+MainWindow::MainWindow(DeviceManager &device_manager,
+       const char *open_file_name,
        QWidget *parent) :
-       QMainWindow(parent)
+       QMainWindow(parent),
+       _device_manager(device_manager)
 {
        setup_ui();
        if (open_file_name) {
@@ -189,12 +195,7 @@ void MainWindow::setup_ui()
        _sampling_bar = new toolbars::SamplingBar(this);
 
        // Populate the device list and select the initially selected device
-       scan_devices();
-       if(!_devices.empty()) {
-               struct sr_dev_inst *const initial_sdi = _devices.front();
-               _sampling_bar->set_selected_device(initial_sdi);
-               _session.set_device(initial_sdi);
-       }
+       update_device_list();
 
        connect(_sampling_bar, SIGNAL(device_selected()), this,
                SLOT(device_selected()));
@@ -212,23 +213,6 @@ void MainWindow::setup_ui()
 
 }
 
-void MainWindow::scan_devices()
-{
-       _devices.clear();
-
-       /* Scan all drivers for all devices. */
-       struct sr_dev_driver **const drivers = sr_driver_list();
-       for (struct sr_dev_driver **driver = drivers; *driver; driver++) {
-               GSList *const devices = sr_driver_scan(*driver, NULL);
-               for (GSList *l = devices; l; l = l->next)
-                       _devices.push_back((sr_dev_inst*)l->data);
-               g_slist_free(devices);
-       }
-
-       assert(_sampling_bar);
-       _sampling_bar->set_device_list(_devices);
-}
-
 void MainWindow::session_error(
        const QString text, const QString info_text)
 {
@@ -237,6 +221,30 @@ void MainWindow::session_error(
                Q_ARG(QString, info_text));
 }
 
+void MainWindow::update_device_list(struct sr_dev_inst *selected_device)
+{
+       assert(_sampling_bar);
+
+       const list<sr_dev_inst*> &devices = _device_manager.devices();
+       _sampling_bar->set_device_list(devices);
+
+       if (!selected_device && !devices.empty()) {
+               // Fall back to the first device in the list.
+               selected_device = devices.front();
+
+               // Try and find the demo device and select that by default
+               BOOST_FOREACH (struct sr_dev_inst *sdi, devices)
+                       if (strcmp(sdi->driver->name, "demo") == 0) {
+                               selected_device = sdi;
+                       }
+       }
+
+       if (selected_device) {
+               _sampling_bar->set_selected_device(selected_device);
+               _session.set_device(selected_device);
+       }
+}
+
 void MainWindow::load_file(QString file_name)
 {
        const QString errorMessage(
@@ -269,20 +277,12 @@ void MainWindow::on_actionOpen_triggered()
 
 void MainWindow::on_actionConnect_triggered()
 {
-       dialogs::Connect dlg(this);
+       dialogs::Connect dlg(this, _device_manager);
        if (!dlg.exec())
                return;
 
        struct sr_dev_inst *const sdi = dlg.get_selected_device();
-       if (sdi) {
-               assert(_sampling_bar);
-
-               _devices.push_back(sdi);
-               _sampling_bar->set_device_list(_devices);
-               _sampling_bar->set_selected_device(sdi);
-
-               _session.set_device(sdi);
-       }
+       update_device_list(sdi);
 }
 
 void MainWindow::on_actionQuit_triggered()
index 8129020348109ec6c395672f27bfa98995f9f9c3..02b792eaa1cd5cc4aed6d8d2b5894edeb935e21f 100644 (file)
@@ -37,6 +37,8 @@ class QWidget;
 
 namespace pv {
 
+class DeviceManager;
+
 namespace toolbars {
 class SamplingBar;
 }
@@ -50,15 +52,24 @@ class MainWindow : public QMainWindow
        Q_OBJECT
 
 public:
-       explicit MainWindow(const char *open_file_name = NULL,
+       explicit MainWindow(DeviceManager &device_manager,
+               const char *open_file_name = NULL,
                QWidget *parent = 0);
 
 private:
        void setup_ui();
-       void scan_devices();
 
        void session_error(const QString text, const QString info_text);
 
+       /**
+        * Updates the device list in the sampling bar, and updates the
+        * selection.
+        * @param selected_device The device to select, or NULL if the
+        * first device in the device list should be selected.
+        */
+       void update_device_list(
+               struct sr_dev_inst *selected_device = NULL);
+
 private slots:
        void load_file(QString file_name);
 
@@ -86,9 +97,9 @@ private slots:
        void capture_state_changed(int state);
 
 private:
+       DeviceManager &_device_manager;
 
        SigSession _session;
-       std::list<sr_dev_inst*> _devices;
 
        pv::view::View *_view;