]> sigrok.org Git - sigrok-meter.git/blame - acquisition.py
Save and restore settings.
[sigrok-meter.git] / acquisition.py
CommitLineData
2e8c2e6e
JS
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
22import qtcompat
23import re
24import sigrok.core as sr
25import time
26
27QtCore = qtcompat.QtCore
28
29class 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()