]> sigrok.org Git - libsigrok.git/blame_incremental - bindings/python/sigrok/core/classes.i
python: Implement equality checks for EnumValue derived classes.
[libsigrok.git] / bindings / python / sigrok / core / classes.i
... / ...
CommitLineData
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2014 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%define DOCSTRING
21"@mainpage API Reference
22
23Introduction
24------------
25
26The pysigrok API provides an object-oriented Python interface to the
27functionality in libsigrok. It is built on top of the sigrok++ C++ API.
28
29Getting started
30---------------
31
32Usage of the pysigrok API needs to begin with a call to Context.create().
33This will create the global libsigrok context and returns a Context object.
34Methods on this object provide access to the hardware drivers, input and output
35formats supported by the library, as well as means of creating other objects
36such as sessions and triggers.
37
38Error handling
39--------------
40
41When any libsigrok C API call returns an error, an Error exception is raised,
42which provides access to the error code and description."
43%enddef
44
45%module(docstring=DOCSTRING) classes
46
47%{
48#include <pygobject.h>
49
50PyObject *GLib;
51PyTypeObject *IOChannel;
52PyTypeObject *PollFD;
53
54#include "config.h"
55
56#if PYGOBJECT_FLAGS_SIGNED
57typedef gint pyg_flags_type;
58#else
59typedef guint pyg_flags_type;
60#endif
61
62%}
63
64%init %{
65 pygobject_init(-1, -1, -1);
66 GLib = PyImport_ImportModule("gi.repository.GLib");
67 IOChannel = (PyTypeObject *) PyObject_GetAttrString(GLib, "IOChannel");
68 PollFD = (PyTypeObject *) PyObject_GetAttrString(GLib, "PollFD");
69%}
70
71/* Map file objects to file descriptors. */
72%typecheck(SWIG_TYPECHECK_POINTER) int fd {
73 $1 = (PyObject_AsFileDescriptor($input) != -1);
74}
75
76%typemap(in) int fd {
77 int fd = PyObject_AsFileDescriptor($input);
78 if (fd == -1)
79 SWIG_exception(SWIG_TypeError,
80 "Expected file object or integer file descriptor");
81 else
82 $1 = fd;
83}
84
85/* Map from Glib::Variant to native Python types. */
86%typemap(out) Glib::VariantBase {
87 GValue *value = g_new0(GValue, 1);
88 g_value_init(value, G_TYPE_VARIANT);
89 g_value_set_variant(value, $1.gobj());
90 PyObject *variant = pyg_value_as_pyobject(value, true);
91 $result = PyObject_CallMethod(variant,
92 const_cast<char *>("unpack"),
93 const_cast<char *>(""), NULL);
94 Py_XDECREF(variant);
95 g_free(value);
96}
97
98/* Map from Glib::IOCondition to GLib.IOCondition. */
99%typecheck(SWIG_TYPECHECK_POINTER) Glib::IOCondition {
100 pyg_flags_type flags;
101 $1 = pygobject_check($input, &PyGFlags_Type) &&
102 (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) != -1);
103}
104
105%typemap(in) Glib::IOCondition {
106 if (!pygobject_check($input, &PyGFlags_Type))
107 SWIG_exception(SWIG_TypeError, "Expected GLib.IOCondition value");
108 pyg_flags_type flags;
109 if (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) == -1)
110 SWIG_exception(SWIG_TypeError, "Not a valid Glib.IOCondition value");
111 $1 = (Glib::IOCondition) flags;
112}
113
114/* And back */
115%typemap(out) Glib::IOCondition {
116 GValue *value = g_new0(GValue, 1);
117 g_value_init(value, G_TYPE_IO_CONDITION);
118 g_value_set_flags(value, &$1);
119 $result = pyg_value_as_pyobject(value, true);
120 g_free(value);
121}
122
123/* Map from GLib.PollFD to Glib::PollFD *. */
124%typecheck(SWIG_TYPECHECK_POINTER) Glib::PollFD {
125 $1 = pygobject_check($input, PollFD);
126}
127
128%typemap(in) Glib::PollFD {
129 if (!pygobject_check($input, PollFD))
130 SWIG_exception(SWIG_TypeError, "Expected GLib.PollFD");
131 PyObject *fd_obj = PyObject_GetAttrString($input, "fd");
132 PyObject *events_obj = PyObject_GetAttrString($input, "events");
133 pyg_flags_type flags;
134 pyg_flags_get_value(G_TYPE_IO_CONDITION, events_obj, &flags);
135 int fd = PyInt_AsLong(fd_obj);
136 Glib::IOCondition events = (Glib::IOCondition) flags;
137 $1 = Glib::PollFD(fd, events);
138}
139
140/* Map from GLib.IOChannel to Glib::IOChannel *. */
141%typecheck(SWIG_TYPECHECK_POINTER) Glib::RefPtr<Glib::IOChannel> {
142 $1 = pygobject_check($input, IOChannel);
143}
144
145%typemap(in) Glib::RefPtr<Glib::IOChannel> {
146 if (!pygobject_check($input, IOChannel))
147 SWIG_exception(SWIG_TypeError, "Expected GLib.IOChannel");
148 $1 = Glib::wrap((GIOChannel *) PyObject_Hash($input), true);
149}
150
151/* Map from callable PyObject to SourceCallbackFunction. */
152%typecheck(SWIG_TYPECHECK_POINTER) sigrok::SourceCallbackFunction {
153 $1 = PyCallable_Check($input);
154}
155
156%typemap(in) sigrok::SourceCallbackFunction {
157 if (!PyCallable_Check($input))
158 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
159
160 $1 = [=] (Glib::IOCondition revents) {
161 auto gstate = PyGILState_Ensure();
162
163 GValue *value = g_new0(GValue, 1);
164 g_value_init(value, G_TYPE_IO_CONDITION);
165 g_value_set_flags(value, revents);
166 auto revents_obj = pyg_value_as_pyobject(value, true);
167 g_free(value);
168
169 auto arglist = Py_BuildValue("(O)", revents_obj);
170
171 auto result = PyEval_CallObject($input, arglist);
172
173 Py_XDECREF(arglist);
174 Py_XDECREF(revents_obj);
175
176 if (PyErr_Occurred() || !PyBool_Check(result))
177 throw sigrok::Error(SR_ERR);
178
179 bool retval = (result == Py_True);
180
181 Py_XDECREF(result);
182
183 PyGILState_Release(gstate);
184
185 return retval;
186 };
187
188 Py_XINCREF($input);
189}
190
191/* Map from callable PyObject to LogCallbackFunction */
192%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
193 $1 = PyCallable_Check($input);
194}
195
196%typemap(in) sigrok::LogCallbackFunction {
197 if (!PyCallable_Check($input))
198 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
199
200 $1 = [=] (const sigrok::LogLevel *loglevel, string message) {
201 auto gstate = PyGILState_Ensure();
202
203 auto log_obj = SWIG_NewPointerObj(
204 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
205
206 auto string_obj = PyString_FromString(message.c_str());
207
208 auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
209
210 auto result = PyEval_CallObject($input, arglist);
211
212 Py_XDECREF(arglist);
213 Py_XDECREF(log_obj);
214 Py_XDECREF(string_obj);
215 Py_XDECREF(result);
216
217 PyGILState_Release(gstate);
218 };
219
220 Py_XINCREF($input);
221}
222
223/* Map from callable PyObject to DatafeedCallbackFunction */
224%typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
225 $1 = PyCallable_Check($input);
226}
227
228%typemap(in) sigrok::DatafeedCallbackFunction {
229 if (!PyCallable_Check($input))
230 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
231
232 $1 = [=] (std::shared_ptr<sigrok::Device> device,
233 std::shared_ptr<sigrok::Packet> packet) {
234 auto gstate = PyGILState_Ensure();
235
236 auto device_obj = SWIG_NewPointerObj(
237 SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
238 SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
239
240 auto packet_obj = SWIG_NewPointerObj(
241 SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
242 SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
243
244 auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
245
246 auto result = PyEval_CallObject($input, arglist);
247
248 Py_XDECREF(arglist);
249 Py_XDECREF(device_obj);
250 Py_XDECREF(packet_obj);
251 Py_XDECREF(result);
252
253 PyGILState_Release(gstate);
254 };
255
256 Py_XINCREF($input);
257}
258
259%{
260
261#include "libsigrok/libsigrok.hpp"
262
263/* Convert from a Python dict to a std::map<std::string, std::string> */
264std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
265{
266 if (!PyDict_Check(dict))
267 throw sigrok::Error(SR_ERR_ARG);
268
269 std::map<std::string, std::string> output;
270
271 PyObject *py_key, *py_value;
272 Py_ssize_t pos = 0;
273
274 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
275 if (!PyString_Check(py_key))
276 throw sigrok::Error(SR_ERR_ARG);
277 if (!PyString_Check(py_value))
278 throw sigrok::Error(SR_ERR_ARG);
279 auto key = PyString_AsString(py_key);
280 auto value = PyString_AsString(py_value);
281 output[key] = value;
282 }
283
284 return output;
285}
286
287/* Convert from a Python type to Glib::Variant, according to config key data type. */
288Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
289{
290 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
291
292 if (type == SR_T_UINT64 && PyInt_Check(input))
293 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
294 if (type == SR_T_UINT64 && PyLong_Check(input))
295 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
296 else if (type == SR_T_STRING && PyString_Check(input))
297 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
298 else if (type == SR_T_BOOL && PyBool_Check(input))
299 return Glib::Variant<bool>::create(input == Py_True);
300 else if (type == SR_T_FLOAT && PyFloat_Check(input))
301 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
302 else if (type == SR_T_INT32 && PyInt_Check(input))
303 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
304 else
305 throw sigrok::Error(SR_ERR_ARG);
306}
307
308/* Convert from a Python type to Glib::Variant, according to Option data type. */
309Glib::VariantBase python_to_variant_by_option(PyObject *input,
310 std::shared_ptr<sigrok::Option> option)
311{
312 GVariantType *type = option->default_value().get_type().gobj();
313
314 if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
315 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
316 if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
317 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
318 else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
319 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
320 else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
321 return Glib::Variant<bool>::create(input == Py_True);
322 else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
323 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
324 else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
325 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
326 else
327 throw sigrok::Error(SR_ERR_ARG);
328}
329
330/* Convert from a Python dict to a std::map<std::string, std::string> */
331std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
332 std::map<std::string, std::shared_ptr<sigrok::Option> > options)
333{
334 if (!PyDict_Check(dict))
335 throw sigrok::Error(SR_ERR_ARG);
336
337 std::map<std::string, Glib::VariantBase> output;
338
339 PyObject *py_key, *py_value;
340 Py_ssize_t pos = 0;
341
342 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
343 if (!PyString_Check(py_key))
344 throw sigrok::Error(SR_ERR_ARG);
345 auto key = PyString_AsString(py_key);
346 auto value = python_to_variant_by_option(py_value, options[key]);
347 output[key] = value;
348 }
349
350 return output;
351}
352
353%}
354
355/* Ignore these methods, we will override them below. */
356%ignore sigrok::Driver::scan;
357%ignore sigrok::InputFormat::create_input;
358%ignore sigrok::OutputFormat::create_output;
359
360%include "doc.i"
361
362%define %attributevector(Class, Type, Name, Get)
363%rename(_ ## Get) sigrok::Class::Get;
364%extend sigrok::Class
365{
366%pythoncode
367{
368 Name = property(_ ## Get)
369}
370}
371%enddef
372
373%define %attributemap(Class, Type, Name, Get)
374%rename(_ ## Get) sigrok::Class::Get;
375%extend sigrok::Class
376{
377%pythoncode
378{
379 Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
380}
381}
382%enddef
383
384%define %enumextras(Class)
385%extend sigrok::Class
386{
387 long __hash__()
388 {
389 return (long) $self;
390 }
391
392%pythoncode
393{
394 def __eq__(self, other):
395 return (type(self) is type(other) and hash(self) == hash(other))
396
397 def __ne__(self, other):
398 return (type(self) is not type(other) or hash(self) != hash(other))
399}
400}
401%enddef
402
403%include "../../../swig/classes.i"
404
405/* Support Driver.scan() with keyword arguments. */
406%extend sigrok::Driver
407{
408 std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
409 {
410 if (!PyDict_Check(dict))
411 throw sigrok::Error(SR_ERR_ARG);
412
413 PyObject *py_key, *py_value;
414 Py_ssize_t pos = 0;
415 std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
416
417 while (PyDict_Next(dict, &pos, &py_key, &py_value))
418 {
419 if (!PyString_Check(py_key))
420 throw sigrok::Error(SR_ERR_ARG);
421 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
422 auto value = python_to_variant_by_key(py_value, key);
423 options[key] = value;
424 }
425
426 return $self->scan(options);
427 }
428}
429
430%pythoncode
431{
432 def _Driver_scan(self, **kwargs):
433 return self._scan_kwargs(kwargs)
434
435 Driver.scan = _Driver_scan
436}
437
438/* Support InputFormat.create_input() with keyword arguments. */
439%extend sigrok::InputFormat
440{
441 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
442 {
443 return $self->create_input(
444 dict_to_map_options(dict, $self->options()));
445 }
446}
447
448%pythoncode
449{
450 def _InputFormat_create_input(self, **kwargs):
451 return self._create_input(kwargs)
452
453 InputFormat.create_input = _InputFormat_create_input
454}
455
456/* Support OutputFormat.create_output() with keyword arguments. */
457%extend sigrok::OutputFormat
458{
459 std::shared_ptr<sigrok::Output> _create_output_kwargs(
460 std::shared_ptr<sigrok::Device> device, PyObject *dict)
461 {
462 return $self->create_output(device,
463 dict_to_map_options(dict, $self->options()));
464 }
465}
466
467%pythoncode
468{
469 def _OutputFormat_create_output(self, device, **kwargs):
470 return self._create_output_kwargs(device, kwargs)
471
472 OutputFormat.create_output = _OutputFormat_create_output
473}
474
475/* Support config_set() with Python input types. */
476%extend sigrok::Configurable
477{
478 void config_set(const ConfigKey *key, PyObject *input)
479 {
480 $self->config_set(key, python_to_variant_by_key(input, key));
481 }
482}