2 ## This file is part of the sigrok-meter project.
4 ## Copyright (C) 2013 Uwe Hermann <uwe@hermann-uwe.de>
5 ## Copyright (C) 2014 Jens Steinhauser <jens.steinhauser@gmail.com>
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.
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.
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
24 import sigrok.core as sr
27 QtCore = qtcompat.QtCore
29 class Acquisition(QtCore.QObject):
30 '''Class that handles the sigrok session and the reception of data.'''
32 '''Signal emitted when new data arrived.'''
33 measured = QtCore.Signal(float, sr.classes.Device, sr.classes.Channel, tuple)
35 '''Signal emitted when the session has stopped.'''
36 stopped = QtCore.Signal()
38 def __init__(self, context):
39 super(self.__class__, self).__init__()
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)
46 def _parse_configstring(self, cs):
47 '''Dissect a config string and return the options as a dictionary.'''
49 def parse_option(k, v):
50 '''Parse the value for a single option.'''
52 ck = sr.ConfigKey.get_by_identifier(k)
54 raise ValueError('No option named "{}".'.format(k))
57 val = ck.parse_string(v)
60 'Invalid value "{}" for option "{}".'.format(v, k))
64 if not re.match('(([^:=]+=[^:=]+)(:[^:=]+=[^:=]+)*)?$', cs):
66 '"{}" is not a valid configuration string.'.format(cs))
72 opts = [tuple(kv.split('=')) for kv in opts]
73 opts = [parse_option(k, v) for (k, v) in opts]
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).'''
80 m = re.match('(?P<name>[^:]+)(?P<opts>(:[^:=]+=[^:=]+)*)$', ds)
82 raise ValueError('"{}" is not a valid driver string.'.format(ds))
84 opts = m.group('opts')[1:]
85 return (m.group('name'), self._parse_configstring(opts))
87 def add_device(self, driverstring, configstring):
88 '''Add a device to the session.'''
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))
95 driver = self.context.drivers[name]
96 devs = driver.scan(**opts)
98 raise RuntimeError('No devices found.')
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)
107 self.session.add_device(device)
110 def is_running(self):
111 '''Return whether the session is running.'''
112 return self.session.is_running()
116 '''Start the session.'''
121 '''Stop the session.'''
122 if self.is_running():
125 def _datafeed_callback(self, device, packet):
128 if packet.type != sr.PacketType.ANALOG:
131 if not len(packet.payload.channels):
134 # TODO: Find a device with multiple channels in one packet.
135 channel = packet.payload.channels[0]
137 # The most recent value.
138 value = packet.payload.data[0][-1]
140 self.measured.emit(now, device, channel,
141 (value, packet.payload.unit, packet.payload.mq_flags))
143 def _stopped_callback(self, **kwargs):