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