Hi Jason,

> 
> I would love to give that a shot!

Sure, I attached a patch that should apply to git head. After
compiling, create two sessions and select one of the logic
analyzers in each. Then, go to the settings dialog and enable the
option. With it enabled, both sessions are started at the same
time, meaning that both logic analyzers capture in parallel.

At high sample rates, this won't work if they're on the same USB
bus - on linux, "lsusb -t" will show you if that's the case and
PV will do as well, albeit in a less obvious manner: usb/2-1.1
and usb/2-1.2 are on the same second USB bus, for example.

Even having them on separate buses didn't help much for me,
however. Maybe you have more success :)


> 
> Is this written in C++?   I'm a Swift developer by day, but I might
> be able to dust off my 10-year old C++ knowledge and lend a hand.

Yeah, C++. Would be cool if you could contribute but there's no
pressure for you to do so.


> 
> Also, what is the status of GPIB protocol decoding?  It is possible I
> might be able to lend a hand there, as that's the hardware project
> I'm working on. 

It works without bugs as far as I'm aware, though with the data
being split across two separate sessions, it'll take some manual
labor to use the GPIB decoder.

One possible way would be to acquire 8 channels through two sessions,
save the data of each into the .sr format (which is just a zip
archive), mux the 2x8-bit samples into 1x16-bit samples using some
little helper tool and open the generated .sr file in PV again.

In the long run, such workarounds won't be necessary because we'll
be able to merge the data on-the-fly but for now, such a workaround
is needed.

Let us know if you run into issues and we'll try to help.

Regards,
 -Soeren


> 
> 
> On Fri, Jul 21, 2017 at 2:11 PM Soeren Apel <soe...@apelpie.net>
> wrote:
> > 
> > Hi Jason,
> > 
> > > 
> > > Is it possible to use multiple logic analyzers together?
> > 
> > It's planned but not yet implemented.
> > 
> > 
> > > 
> > > I'm working on a GPIB to USB converter, and I need to be able to
> > > analyze 16 lines.  I bought two of the cheap 24mHz analyzers, but
> > I
> > > 
> > > don't see a way to use both at the same time in Pulseview.
> > 
> > Even if PV were to support this, it still would be tricky because
> > using two FX2-based logic analyzers on the same USB bus could lead
> > to the bus being too busy to handle all data. This would lead to
> > at least one of the logic analyzers to abort the capture.
> > 
> > That said, if you're willing to build from source and would like
> > to try this, it's trivial to it add to pv/mainwindow.cpp. I can
> > provide you with a proof-of-concept patch if you're interested.
> > 
> > Regards,
> >  -Soeren
> > 
diff --git a/pv/dialogs/settings.cpp b/pv/dialogs/settings.cpp
index ada4118..886bec9 100644
--- a/pv/dialogs/settings.cpp
+++ b/pv/dialogs/settings.cpp
@@ -189,6 +189,10 @@ QWidget *Settings::get_view_settings_form(QWidget *parent) const
 		SLOT(on_view_defaultLogicHeight_changed(int)));
 	trace_view_layout->addRow(tr("Default logic trace height"), default_logic_height_sb);
 
+	cb = create_checkbox(GlobalSettings::Key_Dev_AcquireFromAllDevices,
+		SLOT(on_dev_acquireFromAllDevices_changed(int)));
+	trace_view_layout->addRow(tr("Acquire data from all hardware devices when clicking 'Run'"), cb);
+
 	return form;
 }
 
@@ -400,6 +404,12 @@ void Settings::on_page_changed(QListWidgetItem *current, QListWidgetItem *previo
 	pages->setCurrentIndex(page_list->row(current));
 }
 
+void Settings::on_dev_acquireFromAllDevices_changed(int state)
+{
+	GlobalSettings settings;
+	settings.setValue(GlobalSettings::Key_Dev_AcquireFromAllDevices, state ? true : false);
+}
+
 void Settings::on_view_zoomToFitDuringAcq_changed(int state)
 {
 	GlobalSettings settings;
diff --git a/pv/dialogs/settings.hpp b/pv/dialogs/settings.hpp
index ca8291d..21e55cb 100644
--- a/pv/dialogs/settings.hpp
+++ b/pv/dialogs/settings.hpp
@@ -50,6 +50,7 @@ public:
 
 private Q_SLOTS:
 	void on_page_changed(QListWidgetItem *current, QListWidgetItem *previous);
+	void on_dev_acquireFromAllDevices_changed(int state);
 	void on_view_zoomToFitDuringAcq_changed(int state);
 	void on_view_zoomToFitAfterAcq_changed(int state);
 	void on_view_colouredBG_changed(int state);
diff --git a/pv/globalsettings.cpp b/pv/globalsettings.cpp
index 6ec4a8e..b91357d 100644
--- a/pv/globalsettings.cpp
+++ b/pv/globalsettings.cpp
@@ -30,6 +30,7 @@ using std::multimap;
 
 namespace pv {
 
+const QString GlobalSettings::Key_Dev_AcquireFromAllDevices = "Dev_AcquireFromAllDevices";
 const QString GlobalSettings::Key_View_ZoomToFitDuringAcq = "View_ZoomToFitDuringAcq";
 const QString GlobalSettings::Key_View_ZoomToFitAfterAcq = "View_ZoomToFitAfterAcq";
 const QString GlobalSettings::Key_View_ColouredBG = "View_ColouredBG";
diff --git a/pv/globalsettings.hpp b/pv/globalsettings.hpp
index 7bbff59..e0982a2 100644
--- a/pv/globalsettings.hpp
+++ b/pv/globalsettings.hpp
@@ -40,6 +40,7 @@ class GlobalSettings : public QSettings
 	Q_OBJECT
 
 public:
+	static const QString Key_Dev_AcquireFromAllDevices;
 	static const QString Key_View_ZoomToFitDuringAcq;
 	static const QString Key_View_ZoomToFitAfterAcq;
 	static const QString Key_View_ColouredBG;
diff --git a/pv/mainwindow.cpp b/pv/mainwindow.cpp
index 52b6250..269eb1c 100644
--- a/pv/mainwindow.cpp
+++ b/pv/mainwindow.cpp
@@ -628,20 +628,51 @@ void MainWindow::on_new_session_clicked()
 
 void MainWindow::on_run_stop_clicked()
 {
-	shared_ptr<Session> session = last_focused_session_;
+	GlobalSettings settings;
+	bool all_dev = settings.value(
+		GlobalSettings::Key_Dev_AcquireFromAllDevices).toBool();
 
-	if (!session)
-		return;
+	if (all_dev) {
+		vector< shared_ptr<Session> > hw_sessions;
+
+		// Make a list of all sessions where a hardware device is used
+		for (shared_ptr<Session> s : sessions_) {
+			shared_ptr<devices::HardwareDevice> hw_device =
+				dynamic_pointer_cast< devices::HardwareDevice >(s->device());
+			if (!hw_device)
+				continue;
+			hw_sessions.push_back(s);
+		}
+
+		// Stop all acquisitions if there are any running ones, start all otherwise
+		bool any_running = any_of(hw_sessions.begin(), hw_sessions.end(),
+			[](const shared_ptr<Session> &s)
+				{ return (s->get_capture_state() == Session::AwaitingTrigger) ||
+				(s->get_capture_state() == Session::Running); });
 
-	switch (session->get_capture_state()) {
-	case Session::Stopped:
-		session->start_capture([&](QString message) {
-			session_error("Capture failed", message); });
-		break;
-	case Session::AwaitingTrigger:
-	case Session::Running:
-		session->stop_capture();
-		break;
+		for (shared_ptr<Session> s : hw_sessions)
+			if (any_running)
+				s->stop_capture();
+			else
+				s->start_capture([&](QString message) {
+					session_error("Capture failed", message); });
+
+	} else {
+		shared_ptr<Session> session = last_focused_session_;
+
+		if (!session)
+			return;
+
+		switch (session->get_capture_state()) {
+		case Session::Stopped:
+			session->start_capture([&](QString message) {
+				session_error("Capture failed", message); });
+			break;
+		case Session::AwaitingTrigger:
+		case Session::Running:
+			session->stop_capture();
+			break;
+		}
 	}
 }
 
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to