]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
python: Implement equality checks for EnumValue derived classes.
[libsigrok.git] / bindings / python / sigrok / core / classes.i
CommitLineData
f7740954
ML
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
6a8c1d68
ML
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
f7740954
ML
46
47%{
48#include <pygobject.h>
49
50PyObject *GLib;
51PyTypeObject *IOChannel;
52PyTypeObject *PollFD;
53
0e1a7fe9 54#include "config.h"
abc7146d
ML
55
56#if PYGOBJECT_FLAGS_SIGNED
57typedef gint pyg_flags_type;
58#else
59typedef guint pyg_flags_type;
60#endif
61
f7740954
ML
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 {
abc7146d 100 pyg_flags_type flags;
f7740954
ML
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");
abc7146d 108 pyg_flags_type flags;
f7740954
ML
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");
abc7146d 133 pyg_flags_type flags;
f7740954
ML
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> */
58aa1f83 264std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
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{
9d229ecb 290 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
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))
f90ed2d1 297 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
f7740954
ML
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
58aa1f83
ML
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{
3b161085 312 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
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))
f90ed2d1 319 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
58aa1f83
ML
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
f7740954
ML
353%}
354
355/* Ignore these methods, we will override them below. */
356%ignore sigrok::Driver::scan;
ca3291e3 357%ignore sigrok::InputFormat::create_input;
f7740954
ML
358%ignore sigrok::OutputFormat::create_output;
359
bd4fda24
ML
360%include "doc.i"
361
062430a2 362%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
363%rename(_ ## Get) sigrok::Class::Get;
364%extend sigrok::Class
365{
366%pythoncode
367{
368 Name = property(_ ## Get)
369}
370}
062430a2
ML
371%enddef
372
373%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
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}
062430a2
ML
382%enddef
383
7a36ceac 384%define %enumextras(Class)
f0c0dab5
ML
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}
7a36ceac
ML
401%enddef
402
f7740954
ML
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);
0bc1a761 421 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
f7740954
ML
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
ca3291e3 438/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
439%extend sigrok::InputFormat
440{
ca3291e3 441 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 442 {
ca3291e3 443 return $self->create_input(
3b161085 444 dict_to_map_options(dict, $self->options()));
f7740954
ML
445 }
446}
447
448%pythoncode
449{
ca3291e3
ML
450 def _InputFormat_create_input(self, **kwargs):
451 return self._create_input(kwargs)
f7740954 452
ca3291e3 453 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
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 {
58aa1f83 462 return $self->create_output(device,
3b161085 463 dict_to_map_options(dict, $self->options()));
f7740954
ML
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}