]> sigrok.org Git - sigrok-meter.git/blob - samplingthread.py
Split the program up into multiple files.
[sigrok-meter.git] / samplingthread.py
1 ##
2 ## This file is part of the sigrok-meter project.
3 ##
4 ## Copyright (C) 2013 Uwe Hermann <uwe@hermann-uwe.de>
5 ## Copyright (C) 2014 Jens Steinhauser <jens.steinhauser@gmail.com>
6 ##
7 ## This program is free software; you can redistribute it and/or modify
8 ## it under the terms of the GNU General Public License as published by
9 ## the Free Software Foundation; either version 2 of the License, or
10 ## (at your option) any later version.
11 ##
12 ## This program is distributed in the hope that it will be useful,
13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ## GNU General Public License for more details.
16 ##
17 ## You should have received a copy of the GNU General Public License
18 ## along with this program; if not, write to the Free Software
19 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20 ##
21
22 import qtcompat
23 import sigrok.core as sr
24
25 QtCore = qtcompat.QtCore
26 QtGui = qtcompat.QtGui
27
28 class SamplingThread(QtCore.QObject):
29     '''A class that handles the reception of sigrok packets in the background.'''
30
31     class Worker(QtCore.QObject):
32         '''Helper class that does the actual work in another thread.'''
33
34         '''Signal emitted when new data arrived.'''
35         measured = QtCore.Signal(object, object, object)
36
37         '''Signal emmited in case of an error.'''
38         error = QtCore.Signal(str)
39
40         def __init__(self, context, drivers):
41             super(self.__class__, self).__init__()
42
43             self.context = context
44             self.drivers = drivers
45
46             self.sampling = False
47
48         @QtCore.Slot()
49         def start_sampling(self):
50             devices = []
51             for name, options in self.drivers:
52                 try:
53                     dr = self.context.drivers[name]
54                     devices.append(dr.scan(**options)[0])
55                 except:
56                     self.error.emit(
57                         'Unable to get device for driver "{}".'.format(name))
58                     return
59
60             self.session = self.context.create_session()
61             for dev in devices:
62                 self.session.add_device(dev)
63                 dev.open()
64             self.session.add_datafeed_callback(self.callback)
65             self.session.start()
66             self.sampling = True
67             self.session.run()
68
69             # If sampling is 'True' here, it means that 'stop_sampling()' was
70             # not called, therefore 'session.run()' ended too early, indicating
71             # an error.
72             if self.sampling:
73                 self.error.emit('An error occured during the acquisition.')
74
75         def stop_sampling(self):
76             if self.sampling:
77                 self.sampling = False
78                 self.session.stop()
79
80         def callback(self, device, packet):
81             if not sr:
82                 # In rare cases it can happen that the callback fires while
83                 # the interpreter is shutting down. Then the sigrok module
84                 # is already set to 'None'.
85                 return
86
87             if packet.type != sr.PacketType.ANALOG:
88                 return
89
90             if not len(packet.payload.channels):
91                 return
92
93             # TODO: find a device with multiple channels in one packet
94             channel = packet.payload.channels[0]
95
96             # the most recent value
97             value = packet.payload.data[0][-1]
98
99             self.measured.emit(device, channel,
100                     (value, packet.payload.unit, packet.payload.mq_flags))
101
102     # signal used to start the worker across threads
103     _start_signal = QtCore.Signal()
104
105     def __init__(self, context, drivers):
106         super(self.__class__, self).__init__()
107
108         self.worker = self.Worker(context, drivers)
109         self.thread = QtCore.QThread()
110         self.worker.moveToThread(self.thread)
111
112         self._start_signal.connect(self.worker.start_sampling)
113
114         # expose the signals of the worker
115         self.measured = self.worker.measured
116         self.error = self.worker.error
117
118         self.thread.start()
119
120     def start(self):
121         '''Starts sampling'''
122         self._start_signal.emit()
123
124     def stop(self):
125         '''Stops sampling and the background thread.'''
126         self.worker.stop_sampling()
127         self.thread.quit()
128         self.thread.wait()