]> sigrok.org Git - sigrok-meter.git/blob - acquisition.py
Save and restore settings.
[sigrok-meter.git] / acquisition.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 re
24 import sigrok.core as sr
25 import time
26
27 QtCore = qtcompat.QtCore
28
29 class Acquisition(QtCore.QObject):
30     '''Class that handles the sigrok session and the reception of data.'''
31
32     '''Signal emitted when new data arrived.'''
33     measured = QtCore.Signal(float, sr.classes.Device, sr.classes.Channel, tuple)
34
35     '''Signal emitted when the session has stopped.'''
36     stopped = QtCore.Signal()
37
38     def __init__(self, context):
39         super(self.__class__, self).__init__()
40
41         self.context = context
42         self.session = self.context.create_session()
43         self.session.add_datafeed_callback(self._datafeed_callback)
44         self.session.set_stopped_callback(self._stopped_callback)
45
46     def _parse_configstring(self, cs):
47         '''Dissect a config string and return the options as a dictionary.'''
48
49         def parse_option(k, v):
50             '''Parse the value for a single option.'''
51             try:
52                 ck = sr.ConfigKey.get_by_identifier(k)
53             except:
54                 raise ValueError('No option named "{}".'.format(k))
55
56             try:
57                 val = ck.parse_string(v)
58             except:
59                 raise ValueError(
60                     'Invalid value "{}" for option "{}".'.format(v, k))
61
62             return (k, val)
63
64         if not re.match('(([^:=]+=[^:=]+)(:[^:=]+=[^:=]+)*)?$', cs):
65             raise ValueError(
66                 '"{}" is not a valid configuration string.'.format(cs))
67
68         if not cs:
69             return {}
70
71         opts = cs.split(':')
72         opts = [tuple(kv.split('=')) for kv in opts]
73         opts = [parse_option(k, v) for (k, v) in opts]
74         return dict(opts)
75
76     def _parse_driverstring(self, ds):
77         '''Dissect the driver string and return a tuple consisting of
78         the driver name and the options (as a dictionary).'''
79
80         m = re.match('(?P<name>[^:]+)(?P<opts>(:[^:=]+=[^:=]+)*)$', ds)
81         if not m:
82             raise ValueError('"{}" is not a valid driver string.'.format(ds))
83
84         opts = m.group('opts')[1:]
85         return (m.group('name'), self._parse_configstring(opts))
86
87     def add_device(self, driverstring, configstring):
88         '''Add a device to the session.'''
89
90         # Process driver string.
91         (name, opts) = self._parse_driverstring(driverstring)
92         if not name in self.context.drivers:
93             raise RuntimeError('No driver named "{}".'.format(name))
94
95         driver = self.context.drivers[name]
96         devs = driver.scan(**opts)
97         if not devs:
98             raise RuntimeError('No devices found.')
99
100         device = devs[0]
101
102         # Process configuration string.
103         cfgs = self._parse_configstring(configstring)
104         for k, v in cfgs.items():
105             device.config_set(sr.ConfigKey.get_by_identifier(k), v)
106
107         self.session.add_device(device)
108         device.open()
109
110     def is_running(self):
111         '''Return whether the session is running.'''
112         return self.session.is_running()
113
114     @QtCore.Slot()
115     def start(self):
116         '''Start the session.'''
117         self.session.start()
118
119     @QtCore.Slot()
120     def stop(self):
121         '''Stop the session.'''
122         if self.is_running():
123             self.session.stop()
124
125     def _datafeed_callback(self, device, packet):
126         now = time.time()
127
128         if packet.type != sr.PacketType.ANALOG:
129             return
130
131         if not len(packet.payload.channels):
132             return
133
134         # TODO: find a device with multiple channels in one packet
135         channel = packet.payload.channels[0]
136
137         # The most recent value.
138         value = packet.payload.data[0][-1]
139
140         self.measured.emit(now, device, channel,
141                 (value, packet.payload.unit, packet.payload.mq_flags))
142
143     def _stopped_callback(self, **kwargs):
144         self.stopped.emit()