]> sigrok.org Git - sigrok-meter.git/blobdiff - sigrok-meter
Don't pass the packet.payload between threads.
[sigrok-meter.git] / sigrok-meter
index 8501cfa65ba0c68e727b2d981e168b6e4d309e5a..6f83443a5368df92dc4b4b7a6d20b8d2546edcc3 100755 (executable)
@@ -123,22 +123,18 @@ class SamplingThread(QtCore.QObject):
         '''Helper class that does the actual work in another thread.'''
 
         '''Signal emitted when new data arrived.'''
         '''Helper class that does the actual work in another thread.'''
 
         '''Signal emitted when new data arrived.'''
-        measured = QtCore.Signal(object, object)
+        measured = QtCore.Signal(object, object, object)
 
         '''Signal emmited in case of an error.'''
         error = QtCore.Signal(str)
 
 
         '''Signal emmited in case of an error.'''
         error = QtCore.Signal(str)
 
-        def __init__(self, drivers, loglevel):
+        def __init__(self, context, drivers):
             super(self.__class__, self).__init__()
 
             super(self.__class__, self).__init__()
 
-            self.sampling = False
+            self.context = context
             self.drivers = drivers
 
             self.drivers = drivers
 
-            self.context = sr.Context_create()
-            self.context.log_level = loglevel
-
-            self.sr_pkg_version = self.context.package_version
-            self.sr_lib_version = self.context.lib_version
+            self.sampling = False
 
         @QtCore.Slot()
         def start_sampling(self):
 
         @QtCore.Slot()
         def start_sampling(self):
@@ -173,20 +169,34 @@ class SamplingThread(QtCore.QObject):
                 self.session.stop()
 
         def callback(self, device, packet):
                 self.session.stop()
 
         def callback(self, device, packet):
-            if packet.type == sr.PacketType.ANALOG:
-                self.measured.emit(device, packet.payload)
+            if not sr:
+                # In rare cases it can happen that the callback fires while
+                # the interpreter is shutting down. Then the sigrok module
+                # is already set to 'None'.
+                return
+
+            if packet.type != sr.PacketType.ANALOG:
+                return
+
+            if not len(packet.payload.channels):
+                return
+
+            # TODO: find a device with multiple channels in one packet
+            channel = packet.payload.channels[0]
+
+            # the most recent value
+            value = packet.payload.data[0][-1]
 
 
-            # wait a short time so that in any case we don't flood the GUI
-            # with new data (for example if the demo device is used)
-            self.thread().msleep(100)
+            self.measured.emit(device, channel,
+                    (value, packet.payload.unit, packet.payload.mq_flags))
 
     # signal used to start the worker across threads
     _start_signal = QtCore.Signal()
 
 
     # signal used to start the worker across threads
     _start_signal = QtCore.Signal()
 
-    def __init__(self, drivers, loglevel):
+    def __init__(self, context, drivers):
         super(self.__class__, self).__init__()
 
         super(self.__class__, self).__init__()
 
-        self.worker = self.Worker(drivers, loglevel)
+        self.worker = self.Worker(context, drivers)
         self.thread = QtCore.QThread()
         self.worker.moveToThread(self.thread)
 
         self.thread = QtCore.QThread()
         self.worker.moveToThread(self.thread)
 
@@ -206,17 +216,7 @@ class SamplingThread(QtCore.QObject):
         '''Stops sampling and the background thread.'''
         self.worker.stop_sampling()
         self.thread.quit()
         '''Stops sampling and the background thread.'''
         self.worker.stop_sampling()
         self.thread.quit()
-        # the timeout is needed when the demo device is used, because it
-        # produces so much outstanding data that quitting takes a long time
-        self.thread.wait(500)
-
-    def sr_pkg_version(self):
-        '''Returns the version number of the libsigrok package.'''
-        return self.worker.sr_pkg_version
-
-    def sr_lib_version(self):
-        '''Returns the version number fo the libsigrok library.'''
-        return self.worker.sr_lib_version
+        self.thread.wait()
 
 class MeasurementDataModel(QtGui.QStandardItemModel):
     '''Model to hold the measured values.'''
 
 class MeasurementDataModel(QtGui.QStandardItemModel):
     '''Model to hold the measured values.'''
@@ -234,7 +234,7 @@ class MeasurementDataModel(QtGui.QStandardItemModel):
         # _idRole holds tuples, and using them to sort doesn't work.
         self.setSortRole(MeasurementDataModel.descRole)
 
         # _idRole holds tuples, and using them to sort doesn't work.
         self.setSortRole(MeasurementDataModel.descRole)
 
-        # Used in 'format_mag()' to check against.
+        # Used in 'format_value()' to check against.
         self.inf = float('inf')
 
     def format_unit(self, u):
         self.inf = float('inf')
 
     def format_unit(self, u):
@@ -277,7 +277,7 @@ class MeasurementDataModel(QtGui.QStandardItemModel):
         else:
             return ''
 
         else:
             return ''
 
-    def format_mag(self, mag):
+    def format_value(self, mag):
         if mag == self.inf:
             return u'\u221E'
         return '{:f}'.format(mag)
         if mag == self.inf:
             return u'\u221E'
         return '{:f}'.format(mag)
@@ -315,26 +315,19 @@ class MeasurementDataModel(QtGui.QStandardItemModel):
         self.sort(0)
         return item
 
         self.sort(0)
         return item
 
-    @QtCore.Slot(object, object)
-    def update(self, device, payload):
+    @QtCore.Slot(object, object, object)
+    def update(self, device, channel, data):
         '''Updates the data for the device (+channel) with the most recent
         measurement from the given payload.'''
 
         '''Updates the data for the device (+channel) with the most recent
         measurement from the given payload.'''
 
-        if not len(payload.channels):
-            return
-
-        # TODO: find a device with multiple channels in one packet
-        channel = payload.channels[0]
-
         item = self.getItem(device, channel)
 
         item = self.getItem(device, channel)
 
-        # the most recent value
-        mag = payload.data[0][-1]
+        value, unit, mqflags = data
+        value_str = self.format_value(value)
+        unit_str = self.format_unit(unit)
+        mqflags_str = self.format_mqflags(mqflags)
 
 
-        unit_str = self.format_unit(payload.unit)
-        mqflags_str = self.format_mqflags(payload.mq_flags)
-        mag_str = self.format_mag(mag)
-        disp = ' '.join([mag_str, unit_str, mqflags_str])
+        disp = ' '.join([value_str, unit_str, mqflags_str])
         item.setData(disp, QtCore.Qt.DisplayRole)
 
 class MultimeterDelegate(QtGui.QStyledItemDelegate):
         item.setData(disp, QtCore.Qt.DisplayRole)
 
 class MultimeterDelegate(QtGui.QStyledItemDelegate):
@@ -404,16 +397,18 @@ class EmptyMessageListView(QtGui.QListView):
 class SigrokMeter(QtGui.QMainWindow):
     '''The main window of the application.'''
 
 class SigrokMeter(QtGui.QMainWindow):
     '''The main window of the application.'''
 
-    def __init__(self, thread):
+    def __init__(self, context, drivers):
         super(SigrokMeter, self).__init__()
 
         super(SigrokMeter, self).__init__()
 
+        self.context = context
+
         self.delegate = MultimeterDelegate(self, self.font())
         self.model = MeasurementDataModel(self)
         self.model.rowsInserted.connect(self.modelRowsInserted)
 
         self.setup_ui()
 
         self.delegate = MultimeterDelegate(self, self.font())
         self.model = MeasurementDataModel(self)
         self.model.rowsInserted.connect(self.modelRowsInserted)
 
         self.setup_ui()
 
-        self.thread = thread
+        self.thread = SamplingThread(self.context, drivers)
         self.thread.measured.connect(self.model.update)
         self.thread.error.connect(self.error)
         self.thread.start()
         self.thread.measured.connect(self.model.update)
         self.thread.error.connect(self.error)
         self.thread.start()
@@ -460,6 +455,10 @@ class SigrokMeter(QtGui.QMainWindow):
         self.setCentralWidget(self.listView)
         self.centralWidget().setContentsMargins(0, 0, 0, 0)
 
         self.setCentralWidget(self.listView)
         self.centralWidget().setContentsMargins(0, 0, 0, 0)
 
+    def closeEvent(self, event):
+        self.thread.stop()
+        event.accept()
+
     @QtCore.Slot()
     def show_about(self):
         text = textwrap.dedent('''\
     @QtCore.Slot()
     def show_about(self):
         text = textwrap.dedent('''\
@@ -475,7 +474,7 @@ class SigrokMeter(QtGui.QMainWindow):
                 <a href='http://www.gnu.org/licenses/gpl.html'>
                          http://www.gnu.org/licenses/gpl.html</a>
             </div>
                 <a href='http://www.gnu.org/licenses/gpl.html'>
                          http://www.gnu.org/licenses/gpl.html</a>
             </div>
-        '''.format(self.thread.sr_pkg_version(), self.thread.sr_lib_version()))
+        '''.format(self.context.package_version, self.context.lib_version))
 
         QtGui.QMessageBox.about(self, 'About sigrok-meter', text)
 
 
         QtGui.QMessageBox.about(self, 'About sigrok-meter', text)
 
@@ -494,12 +493,11 @@ class SigrokMeter(QtGui.QMainWindow):
         self.listView.setMinimumHeight(dh * rows)
 
 if __name__ == '__main__':
         self.listView.setMinimumHeight(dh * rows)
 
 if __name__ == '__main__':
-    thread = SamplingThread(args['drivers'], args['loglevel'])
+    context = sr.Context_create()
+    context.log_level = args['loglevel']
 
     app = QtGui.QApplication([])
 
     app = QtGui.QApplication([])
-    s = SigrokMeter(thread)
+    s = SigrokMeter(context, args['drivers'])
     s.show()
 
     s.show()
 
-    r = app.exec_()
-    thread.stop()
-    sys.exit(r)
+    sys.exit(app.exec_())