]>
Commit | Line | Data |
---|---|---|
d8f6e041 ML |
1 | ## |
2 | ## This file is part of the sigrok project. | |
3 | ## | |
4 | ## Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li> | |
5 | ## | |
6 | ## This program is free software: you can redistribute it and/or modify | |
7 | ## it under the terms of the GNU General Public License as published by | |
8 | ## the Free Software Foundation, either version 3 of the License, or | |
9 | ## (at your option) any later version. | |
10 | ## | |
11 | ## This program is distributed in the hope that it will be useful, | |
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ## GNU General Public License for more details. | |
15 | ## | |
16 | ## You should have received a copy of the GNU General Public License | |
17 | ## along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | ## | |
19 | ||
20 | from functools import partial | |
21 | from fractions import Fraction | |
1cad2115 ML |
22 | from .lowlevel import * |
23 | from . import lowlevel | |
d8f6e041 ML |
24 | import itertools |
25 | ||
816aed6c | 26 | __all__ = ['Error', 'Context', 'Driver', 'Device', 'Session', 'Packet', 'Log'] |
d8f6e041 ML |
27 | |
28 | class Error(Exception): | |
29 | ||
30 | def __str__(self): | |
31 | return sr_strerror(self.args[0]) | |
32 | ||
33 | def check(result): | |
34 | if result != SR_OK: | |
35 | raise Error(result) | |
36 | ||
37 | def config_key(name): | |
38 | if not name.lower() == name: | |
39 | raise AttributeError | |
40 | key_name = "SR_CONF_" + name.upper() | |
41 | return getattr(lowlevel, key_name) | |
42 | ||
43 | def gvariant_to_python(value): | |
44 | type_string = g_variant_get_type_string(value) | |
45 | if type_string == 't': | |
46 | return g_variant_get_uint64(value) | |
47 | if type_string == 'b': | |
48 | return g_variant_get_bool(value) | |
49 | if type_string == 'd': | |
50 | return g_variant_get_double(value) | |
51 | if type_string == 's': | |
52 | return g_variant_get_string(value, None) | |
53 | if type_string == '(tt)': | |
54 | return Fraction( | |
55 | g_variant_get_uint64(g_variant_get_child_value(value, 0)), | |
56 | g_variant_get_uint64(g_variant_get_child_value(value, 1))) | |
1cad2115 | 57 | raise NotImplementedError( |
d8f6e041 ML |
58 | "Can't convert GVariant type '%s' to a Python type." % type_string) |
59 | ||
60 | def python_to_gvariant(value): | |
61 | if isinstance(value, int): | |
62 | return g_variant_new_uint64(value) | |
63 | if isinstance(value, bool): | |
64 | return g_variant_new_boolean(value) | |
65 | if isinstance(value, float): | |
66 | return g_variant_new_double(value) | |
67 | if isinstance(value, str): | |
68 | return g_variant_new_string(value) | |
69 | if isinstance(value, Fraction): | |
70 | array = new_gvariant_ptr_array(2) | |
71 | gvariant_ptr_array_setitem(array, 0, value.numerator) | |
72 | gvariant_ptr_array_setitem(array, 1, value.denominator) | |
73 | result = g_variant_new_tuple(array, 2) | |
74 | delete_gvariant_ptr_array(array) | |
75 | return result | |
1cad2115 | 76 | raise NotImplementedError( |
d8f6e041 ML |
77 | "Can't convert Python '%s' to a GVariant." % type(value)) |
78 | ||
79 | def callback_wrapper(session, callback, device_ptr, packet_ptr): | |
80 | device = session.context._devices[int(device_ptr.this)] | |
81 | packet = Packet(session, packet_ptr) | |
82 | callback(device, packet) | |
83 | ||
84 | class Context(object): | |
85 | ||
86 | def __init__(self): | |
87 | context_ptr_ptr = new_sr_context_ptr_ptr() | |
88 | check(sr_init(context_ptr_ptr)) | |
89 | self.struct = sr_context_ptr_ptr_value(context_ptr_ptr) | |
90 | self._drivers = None | |
91 | self._devices = {} | |
92 | self.session = None | |
93 | ||
94 | def __del__(self): | |
95 | sr_exit(self.struct) | |
96 | ||
97 | @property | |
98 | def drivers(self): | |
99 | if not self._drivers: | |
100 | self._drivers = {} | |
101 | driver_list = sr_driver_list() | |
102 | for i in itertools.count(): | |
103 | driver_ptr = sr_dev_driver_ptr_array_getitem(driver_list, i) | |
104 | if driver_ptr: | |
105 | self._drivers[driver_ptr.name] = Driver(self, driver_ptr) | |
106 | else: | |
107 | break | |
108 | return self._drivers | |
109 | ||
110 | class Driver(object): | |
111 | ||
112 | def __init__(self, context, struct): | |
113 | self.context = context | |
114 | self.struct = struct | |
115 | self._initialized = False | |
116 | ||
117 | @property | |
118 | def name(self): | |
119 | return self.struct.name | |
120 | ||
121 | def scan(self): | |
122 | if not self._initialized: | |
123 | check(sr_driver_init(self.context.struct, self.struct)) | |
124 | self._initialized = True | |
125 | devices = [] | |
126 | device_list = sr_driver_scan(self.struct, None) | |
127 | device_list_item = device_list | |
128 | while device_list_item: | |
129 | ptr = device_list_item.data | |
130 | device_ptr = gpointer_to_sr_dev_inst_ptr(ptr) | |
131 | devices.append(Device(self, device_ptr)) | |
132 | device_list_item = device_list_item.next | |
133 | g_slist_free(device_list) | |
134 | return devices | |
135 | ||
136 | class Device(object): | |
137 | ||
138 | def __new__(cls, driver, struct): | |
139 | address = int(struct.this) | |
140 | if address not in driver.context._devices: | |
141 | device = super(Device, cls).__new__(cls, driver, struct) | |
142 | driver.context._devices[address] = device | |
143 | return driver.context._devices[address] | |
144 | ||
145 | def __init__(self, driver, struct): | |
146 | self.driver = driver | |
147 | self.struct = struct | |
148 | ||
149 | def __getattr__(self, name): | |
150 | key = config_key(name) | |
151 | data = new_gvariant_ptr_ptr() | |
152 | try: | |
153 | check(sr_config_get(self.driver.struct, key, data, self.struct)) | |
154 | except Error as error: | |
0021b077 | 155 | if error.errno == SR_ERR_NA: |
1cad2115 | 156 | raise NotImplementedError( |
d8f6e041 ML |
157 | "Device does not implement %s" % name) |
158 | else: | |
159 | raise AttributeError | |
160 | value = gvariant_ptr_ptr_value(data) | |
161 | return gvariant_to_python(value) | |
162 | ||
163 | def __setattr__(self, name, value): | |
164 | try: | |
165 | key = config_key(name) | |
166 | except AttributeError: | |
167 | super(Device, self).__setattr__(name, value) | |
168 | return | |
169 | check(sr_config_set(self.struct, key, python_to_gvariant(value))) | |
170 | ||
171 | @property | |
172 | def vendor(self): | |
173 | return self.struct.vendor | |
174 | ||
175 | @property | |
176 | def model(self): | |
177 | return self.struct.model | |
178 | ||
179 | @property | |
180 | def version(self): | |
181 | return self.struct.version | |
182 | ||
183 | class Session(object): | |
184 | ||
185 | def __init__(self, context): | |
186 | assert context.session is None | |
187 | self.context = context | |
188 | self.struct = sr_session_new() | |
189 | context.session = self | |
190 | ||
191 | def __del__(self): | |
192 | check(sr_session_destroy()) | |
193 | ||
194 | def add_device(self, device): | |
195 | check(sr_session_dev_add(device.struct)) | |
196 | ||
197 | def add_callback(self, callback): | |
198 | wrapper = partial(callback_wrapper, self, callback) | |
199 | check(sr_session_datafeed_python_callback_add(wrapper)) | |
200 | ||
201 | def start(self): | |
202 | check(sr_session_start()) | |
203 | ||
204 | def run(self): | |
205 | check(sr_session_run()) | |
206 | ||
207 | def stop(self): | |
208 | check(sr_session_stop()) | |
209 | ||
210 | class Packet(object): | |
211 | ||
212 | def __init__(self, session, struct): | |
213 | self.session = session | |
214 | self.struct = struct | |
215 | self._payload = None | |
216 | ||
217 | @property | |
218 | def type(self): | |
219 | return self.struct.type | |
220 | ||
221 | @property | |
222 | def payload(self): | |
223 | if self._payload is None: | |
224 | pointer = self.struct.payload | |
225 | if self.struct.type == SR_DF_LOGIC: | |
226 | self._payload = Logic(self, | |
227 | void_ptr_to_sr_datafeed_logic_ptr(pointer)) | |
15574a3c ML |
228 | elif self.struct.type == SR_DF_ANALOG: |
229 | self._payload = Analog(self, | |
230 | void_ptr_to_sr_datafeed_analog_ptr(pointer)) | |
d8f6e041 | 231 | else: |
1cad2115 | 232 | raise NotImplementedError( |
d8f6e041 ML |
233 | "No Python mapping for packet type %ѕ" % self.struct.type) |
234 | return self._payload | |
235 | ||
236 | class Logic(object): | |
237 | ||
238 | def __init__(self, packet, struct): | |
239 | self.packet = packet | |
240 | self.struct = struct | |
241 | self._data = None | |
242 | ||
243 | @property | |
244 | def data(self): | |
245 | if self._data is None: | |
246 | self._data = cdata(self.struct.data, self.struct.length) | |
247 | return self._data | |
248 | ||
15574a3c ML |
249 | class Analog(object): |
250 | ||
251 | def __init__(self, packet, struct): | |
252 | self.packet = packet | |
253 | self.struct = struct | |
254 | self._data = None | |
255 | ||
256 | @property | |
257 | def num_samples(self): | |
258 | return self.struct.num_samples | |
259 | ||
c2ec42ce UH |
260 | @property |
261 | def mq(self): | |
262 | return self.struct.mq | |
263 | ||
264 | @property | |
265 | def unit(self): | |
266 | return self.struct.unit | |
267 | ||
268 | @property | |
269 | def mqflags(self): | |
270 | return self.struct.mqflags | |
271 | ||
15574a3c ML |
272 | @property |
273 | def data(self): | |
274 | if self._data is None: | |
275 | self._data = float_array.frompointer(self.struct.data) | |
276 | return self._data | |
277 | ||
816aed6c UH |
278 | class Log(object): |
279 | ||
280 | NONE = SR_LOG_NONE | |
281 | ERR = SR_LOG_ERR | |
282 | WARN = SR_LOG_WARN | |
283 | INFO = SR_LOG_INFO | |
284 | DBG = SR_LOG_DBG | |
285 | SPEW = SR_LOG_SPEW | |
286 | ||
287 | @property | |
288 | def level(self): | |
289 | return sr_log_loglevel_get() | |
290 | ||
291 | @level.setter | |
292 | def level(self, l): | |
293 | check(sr_log_loglevel_set(l)) | |
294 | ||
295 | @property | |
296 | def domain(self): | |
297 | return sr_log_logdomain_get() | |
298 | ||
299 | @domain.setter | |
300 | def domain(self, d): | |
301 | check(sr_log_logdomain_set(d)) | |
302 | ||
d8f6e041 ML |
303 | for symbol_name in dir(lowlevel): |
304 | prefix = 'SR_DF_' | |
305 | if symbol_name.startswith(prefix): | |
306 | name = symbol_name[len(prefix):] | |
307 | setattr(Packet, name, getattr(lowlevel, symbol_name)) |