]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
python: Fix the build for Python >= 3.
[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
52ff4f6a 27functionality in libsigrok. It is built on top of the libsigrokcxx C++ API.
6a8c1d68
ML
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%{
aae2273b 48#include <stdio.h>
f7740954 49#include <pygobject.h>
ed6b4c47 50#include <numpy/arrayobject.h>
f7740954 51
aae2273b 52PyObject *PyGObject_lib;
f7740954
ML
53PyObject *GLib;
54PyTypeObject *IOChannel;
55PyTypeObject *PollFD;
56
0e1a7fe9 57#include "config.h"
abc7146d
ML
58
59#if PYGOBJECT_FLAGS_SIGNED
60typedef gint pyg_flags_type;
61#else
62typedef guint pyg_flags_type;
63#endif
64
f7740954
ML
65%}
66
67%init %{
aae2273b
AG
68 PyGObject_lib = pygobject_init(-1, -1, -1);
69 if (!PyGObject_lib)
70 fprintf(stderr, "pygobject initialization failed.\n");
f7740954 71 GLib = PyImport_ImportModule("gi.repository.GLib");
aae2273b
AG
72 /*
73 * This check can't save us if the import fails, but at least it gives us
74 * a starting point to trace the issue versus straight out crashing.
75 */
76 if (!GLib) {
77 fprintf(stderr, "Import of gi.repository.GLib failed.\n");
a2e4d882
UH
78#if PY_VERSION_HEX >= 0x03000000
79 return NULL;
80#else
aae2273b 81 return;
a2e4d882 82#endif
aae2273b 83 }
f7740954
ML
84 IOChannel = (PyTypeObject *) PyObject_GetAttrString(GLib, "IOChannel");
85 PollFD = (PyTypeObject *) PyObject_GetAttrString(GLib, "PollFD");
ed6b4c47 86 import_array();
f7740954
ML
87%}
88
89/* Map file objects to file descriptors. */
90%typecheck(SWIG_TYPECHECK_POINTER) int fd {
91 $1 = (PyObject_AsFileDescriptor($input) != -1);
92}
93
94%typemap(in) int fd {
95 int fd = PyObject_AsFileDescriptor($input);
96 if (fd == -1)
97 SWIG_exception(SWIG_TypeError,
98 "Expected file object or integer file descriptor");
99 else
100 $1 = fd;
101}
102
103/* Map from Glib::Variant to native Python types. */
104%typemap(out) Glib::VariantBase {
105 GValue *value = g_new0(GValue, 1);
106 g_value_init(value, G_TYPE_VARIANT);
107 g_value_set_variant(value, $1.gobj());
108 PyObject *variant = pyg_value_as_pyobject(value, true);
109 $result = PyObject_CallMethod(variant,
110 const_cast<char *>("unpack"),
111 const_cast<char *>(""), NULL);
112 Py_XDECREF(variant);
113 g_free(value);
114}
115
116/* Map from Glib::IOCondition to GLib.IOCondition. */
117%typecheck(SWIG_TYPECHECK_POINTER) Glib::IOCondition {
abc7146d 118 pyg_flags_type flags;
f7740954
ML
119 $1 = pygobject_check($input, &PyGFlags_Type) &&
120 (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) != -1);
121}
122
123%typemap(in) Glib::IOCondition {
124 if (!pygobject_check($input, &PyGFlags_Type))
125 SWIG_exception(SWIG_TypeError, "Expected GLib.IOCondition value");
abc7146d 126 pyg_flags_type flags;
f7740954
ML
127 if (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) == -1)
128 SWIG_exception(SWIG_TypeError, "Not a valid Glib.IOCondition value");
129 $1 = (Glib::IOCondition) flags;
130}
131
132/* And back */
133%typemap(out) Glib::IOCondition {
134 GValue *value = g_new0(GValue, 1);
135 g_value_init(value, G_TYPE_IO_CONDITION);
136 g_value_set_flags(value, &$1);
137 $result = pyg_value_as_pyobject(value, true);
138 g_free(value);
139}
140
141/* Map from GLib.PollFD to Glib::PollFD *. */
142%typecheck(SWIG_TYPECHECK_POINTER) Glib::PollFD {
143 $1 = pygobject_check($input, PollFD);
144}
145
146%typemap(in) Glib::PollFD {
147 if (!pygobject_check($input, PollFD))
148 SWIG_exception(SWIG_TypeError, "Expected GLib.PollFD");
149 PyObject *fd_obj = PyObject_GetAttrString($input, "fd");
150 PyObject *events_obj = PyObject_GetAttrString($input, "events");
abc7146d 151 pyg_flags_type flags;
f7740954
ML
152 pyg_flags_get_value(G_TYPE_IO_CONDITION, events_obj, &flags);
153 int fd = PyInt_AsLong(fd_obj);
154 Glib::IOCondition events = (Glib::IOCondition) flags;
155 $1 = Glib::PollFD(fd, events);
156}
157
158/* Map from GLib.IOChannel to Glib::IOChannel *. */
159%typecheck(SWIG_TYPECHECK_POINTER) Glib::RefPtr<Glib::IOChannel> {
160 $1 = pygobject_check($input, IOChannel);
161}
162
163%typemap(in) Glib::RefPtr<Glib::IOChannel> {
164 if (!pygobject_check($input, IOChannel))
165 SWIG_exception(SWIG_TypeError, "Expected GLib.IOChannel");
166 $1 = Glib::wrap((GIOChannel *) PyObject_Hash($input), true);
167}
168
169/* Map from callable PyObject to SourceCallbackFunction. */
170%typecheck(SWIG_TYPECHECK_POINTER) sigrok::SourceCallbackFunction {
171 $1 = PyCallable_Check($input);
172}
173
174%typemap(in) sigrok::SourceCallbackFunction {
175 if (!PyCallable_Check($input))
176 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
177
178 $1 = [=] (Glib::IOCondition revents) {
179 auto gstate = PyGILState_Ensure();
180
181 GValue *value = g_new0(GValue, 1);
182 g_value_init(value, G_TYPE_IO_CONDITION);
183 g_value_set_flags(value, revents);
184 auto revents_obj = pyg_value_as_pyobject(value, true);
185 g_free(value);
186
187 auto arglist = Py_BuildValue("(O)", revents_obj);
188
189 auto result = PyEval_CallObject($input, arglist);
190
191 Py_XDECREF(arglist);
192 Py_XDECREF(revents_obj);
193
75fb3036
ML
194 bool completed = !PyErr_Occurred();
195
196 if (!completed)
197 PyErr_Print();
198
199 bool valid_result = (completed && PyBool_Check(result));
f7740954 200
75fb3036
ML
201 if (completed && !valid_result)
202 {
203 PyErr_SetString(PyExc_TypeError,
204 "EventSource callback did not return a boolean");
205 PyErr_Print();
206 }
207
208 bool retval = (valid_result && result == Py_True);
f7740954
ML
209
210 Py_XDECREF(result);
211
212 PyGILState_Release(gstate);
213
75fb3036
ML
214 if (!valid_result)
215 throw sigrok::Error(SR_ERR);
216
f7740954
ML
217 return retval;
218 };
219
220 Py_XINCREF($input);
221}
222
223/* Map from callable PyObject to LogCallbackFunction */
224%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
225 $1 = PyCallable_Check($input);
226}
227
228%typemap(in) sigrok::LogCallbackFunction {
229 if (!PyCallable_Check($input))
230 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
231
682fb08c 232 $1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
f7740954
ML
233 auto gstate = PyGILState_Ensure();
234
235 auto log_obj = SWIG_NewPointerObj(
236 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
237
238 auto string_obj = PyString_FromString(message.c_str());
239
240 auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
241
242 auto result = PyEval_CallObject($input, arglist);
243
244 Py_XDECREF(arglist);
245 Py_XDECREF(log_obj);
246 Py_XDECREF(string_obj);
75fb3036
ML
247
248 bool completed = !PyErr_Occurred();
249
250 if (!completed)
251 PyErr_Print();
252
253 bool valid_result = (completed && result == Py_None);
254
f7740954
ML
255 Py_XDECREF(result);
256
75fb3036
ML
257 if (completed && !valid_result)
258 {
259 PyErr_SetString(PyExc_TypeError,
260 "Log callback did not return None");
261 PyErr_Print();
262 }
263
f7740954 264 PyGILState_Release(gstate);
75fb3036
ML
265
266 if (!valid_result)
267 throw sigrok::Error(SR_ERR);
f7740954
ML
268 };
269
270 Py_XINCREF($input);
271}
272
273/* Map from callable PyObject to DatafeedCallbackFunction */
274%typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
275 $1 = PyCallable_Check($input);
276}
277
278%typemap(in) sigrok::DatafeedCallbackFunction {
279 if (!PyCallable_Check($input))
280 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
281
282 $1 = [=] (std::shared_ptr<sigrok::Device> device,
283 std::shared_ptr<sigrok::Packet> packet) {
284 auto gstate = PyGILState_Ensure();
285
286 auto device_obj = SWIG_NewPointerObj(
287 SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
288 SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
289
290 auto packet_obj = SWIG_NewPointerObj(
291 SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
292 SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
293
294 auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
295
296 auto result = PyEval_CallObject($input, arglist);
297
298 Py_XDECREF(arglist);
299 Py_XDECREF(device_obj);
300 Py_XDECREF(packet_obj);
75fb3036
ML
301
302 bool completed = !PyErr_Occurred();
303
304 if (!completed)
305 PyErr_Print();
306
307 bool valid_result = (completed && result == Py_None);
308
f7740954
ML
309 Py_XDECREF(result);
310
75fb3036
ML
311 if (completed && !valid_result)
312 {
313 PyErr_SetString(PyExc_TypeError,
314 "Datafeed callback did not return None");
315 PyErr_Print();
316 }
317
f7740954 318 PyGILState_Release(gstate);
75fb3036
ML
319
320 if (!valid_result)
321 throw sigrok::Error(SR_ERR);
f7740954
ML
322 };
323
324 Py_XINCREF($input);
325}
326
ea22dc10
ML
327/* Cast PacketPayload pointers to correct subclass type. */
328%ignore sigrok::Packet::payload;
329
330%extend sigrok::Packet
331{
332 std::shared_ptr<sigrok::Header> _payload_header()
333 {
334 return dynamic_pointer_cast<sigrok::Header>($self->payload());
335 }
336 std::shared_ptr<sigrok::Meta> _payload_meta()
337 {
338 return dynamic_pointer_cast<sigrok::Meta>($self->payload());
339 }
340 std::shared_ptr<sigrok::Analog> _payload_analog()
341 {
342 return dynamic_pointer_cast<sigrok::Analog>($self->payload());
343 }
344 std::shared_ptr<sigrok::Logic> _payload_logic()
345 {
346 return dynamic_pointer_cast<sigrok::Logic>($self->payload());
347 }
348}
349
350%extend sigrok::Packet
351{
352%pythoncode
353{
354 def _payload(self):
355 if self.type == PacketType.HEADER:
356 return self._payload_header()
357 elif self.type == PacketType.META:
358 return self._payload_meta()
359 elif self.type == PacketType.LOGIC:
360 return self._payload_logic()
361 elif self.type == PacketType.ANALOG:
362 return self._payload_analog()
363 else:
364 return None
365
366 payload = property(_payload)
367}
368}
369
f7740954
ML
370%{
371
161dc24d 372#include "libsigrokcxx/libsigrokcxx.hpp"
f7740954
ML
373
374/* Convert from a Python dict to a std::map<std::string, std::string> */
58aa1f83 375std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
376{
377 if (!PyDict_Check(dict))
378 throw sigrok::Error(SR_ERR_ARG);
379
380 std::map<std::string, std::string> output;
381
382 PyObject *py_key, *py_value;
383 Py_ssize_t pos = 0;
384
385 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
386 if (!PyString_Check(py_key))
387 throw sigrok::Error(SR_ERR_ARG);
388 if (!PyString_Check(py_value))
389 throw sigrok::Error(SR_ERR_ARG);
390 auto key = PyString_AsString(py_key);
391 auto value = PyString_AsString(py_value);
392 output[key] = value;
393 }
394
395 return output;
396}
397
398/* Convert from a Python type to Glib::Variant, according to config key data type. */
399Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
400{
9d229ecb 401 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
402
403 if (type == SR_T_UINT64 && PyInt_Check(input))
404 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
405 if (type == SR_T_UINT64 && PyLong_Check(input))
406 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
407 else if (type == SR_T_STRING && PyString_Check(input))
f90ed2d1 408 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
f7740954
ML
409 else if (type == SR_T_BOOL && PyBool_Check(input))
410 return Glib::Variant<bool>::create(input == Py_True);
411 else if (type == SR_T_FLOAT && PyFloat_Check(input))
412 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
413 else if (type == SR_T_INT32 && PyInt_Check(input))
414 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
415 else
416 throw sigrok::Error(SR_ERR_ARG);
417}
418
58aa1f83
ML
419/* Convert from a Python type to Glib::Variant, according to Option data type. */
420Glib::VariantBase python_to_variant_by_option(PyObject *input,
421 std::shared_ptr<sigrok::Option> option)
422{
3b161085 423 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
424
425 if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
426 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
427 if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
428 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
429 else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
f90ed2d1 430 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
58aa1f83
ML
431 else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
432 return Glib::Variant<bool>::create(input == Py_True);
433 else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
434 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
435 else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
436 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
437 else
438 throw sigrok::Error(SR_ERR_ARG);
439}
440
441/* Convert from a Python dict to a std::map<std::string, std::string> */
442std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
443 std::map<std::string, std::shared_ptr<sigrok::Option> > options)
444{
445 if (!PyDict_Check(dict))
446 throw sigrok::Error(SR_ERR_ARG);
447
448 std::map<std::string, Glib::VariantBase> output;
449
450 PyObject *py_key, *py_value;
451 Py_ssize_t pos = 0;
452
453 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
454 if (!PyString_Check(py_key))
455 throw sigrok::Error(SR_ERR_ARG);
456 auto key = PyString_AsString(py_key);
457 auto value = python_to_variant_by_option(py_value, options[key]);
458 output[key] = value;
459 }
460
461 return output;
462}
463
f7740954
ML
464%}
465
466/* Ignore these methods, we will override them below. */
ed6b4c47 467%ignore sigrok::Analog::data;
f7740954 468%ignore sigrok::Driver::scan;
ca3291e3 469%ignore sigrok::InputFormat::create_input;
f7740954
ML
470%ignore sigrok::OutputFormat::create_output;
471
bd4fda24
ML
472%include "doc.i"
473
062430a2 474%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
475%rename(_ ## Get) sigrok::Class::Get;
476%extend sigrok::Class
477{
478%pythoncode
479{
480 Name = property(_ ## Get)
481}
482}
062430a2
ML
483%enddef
484
485%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
486%rename(_ ## Get) sigrok::Class::Get;
487%extend sigrok::Class
488{
489%pythoncode
490{
491 Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
492}
493}
062430a2
ML
494%enddef
495
7a36ceac 496%define %enumextras(Class)
f0c0dab5
ML
497%extend sigrok::Class
498{
499 long __hash__()
500 {
501 return (long) $self;
502 }
503
504%pythoncode
505{
506 def __eq__(self, other):
507 return (type(self) is type(other) and hash(self) == hash(other))
508
509 def __ne__(self, other):
510 return (type(self) is not type(other) or hash(self) != hash(other))
511}
512}
7a36ceac
ML
513%enddef
514
f7740954
ML
515%include "../../../swig/classes.i"
516
517/* Support Driver.scan() with keyword arguments. */
518%extend sigrok::Driver
519{
520 std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
521 {
522 if (!PyDict_Check(dict))
523 throw sigrok::Error(SR_ERR_ARG);
524
525 PyObject *py_key, *py_value;
526 Py_ssize_t pos = 0;
527 std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
528
529 while (PyDict_Next(dict, &pos, &py_key, &py_value))
530 {
531 if (!PyString_Check(py_key))
532 throw sigrok::Error(SR_ERR_ARG);
0bc1a761 533 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
f7740954
ML
534 auto value = python_to_variant_by_key(py_value, key);
535 options[key] = value;
536 }
537
538 return $self->scan(options);
539 }
540}
541
542%pythoncode
543{
544 def _Driver_scan(self, **kwargs):
545 return self._scan_kwargs(kwargs)
546
547 Driver.scan = _Driver_scan
548}
549
ca3291e3 550/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
551%extend sigrok::InputFormat
552{
ca3291e3 553 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 554 {
ca3291e3 555 return $self->create_input(
3b161085 556 dict_to_map_options(dict, $self->options()));
f7740954
ML
557 }
558}
559
560%pythoncode
561{
ca3291e3
ML
562 def _InputFormat_create_input(self, **kwargs):
563 return self._create_input(kwargs)
f7740954 564
ca3291e3 565 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
566}
567
568/* Support OutputFormat.create_output() with keyword arguments. */
569%extend sigrok::OutputFormat
570{
571 std::shared_ptr<sigrok::Output> _create_output_kwargs(
572 std::shared_ptr<sigrok::Device> device, PyObject *dict)
573 {
58aa1f83 574 return $self->create_output(device,
3b161085 575 dict_to_map_options(dict, $self->options()));
f7740954
ML
576 }
577}
578
579%pythoncode
580{
581 def _OutputFormat_create_output(self, device, **kwargs):
582 return self._create_output_kwargs(device, kwargs)
583
584 OutputFormat.create_output = _OutputFormat_create_output
585}
586
587/* Support config_set() with Python input types. */
588%extend sigrok::Configurable
589{
590 void config_set(const ConfigKey *key, PyObject *input)
591 {
592 $self->config_set(key, python_to_variant_by_key(input, key));
593 }
594}
ed6b4c47
ML
595
596/* Return NumPy array from Analog::data(). */
597%extend sigrok::Analog
598{
599 PyObject * _data()
600 {
601 int nd = 2;
602 npy_intp dims[2];
603 dims[0] = $self->channels().size();
604 dims[1] = $self->num_samples();
605 int typenum = NPY_FLOAT;
606 void *data = $self->data_pointer();
607 return PyArray_SimpleNewFromData(nd, dims, typenum, data);
608 }
609
610%pythoncode
611{
612 data = property(_data)
613}
614}