]> sigrok.org Git - libsigrok.git/blame_incremental - bindings/python/sigrok/core/classes.i
cxx: Rename include/libsigrok/ to include/libsigrokcxx/.
[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 libsigrokcxx 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#include <numpy/arrayobject.h>
50
51PyObject *GLib;
52PyTypeObject *IOChannel;
53PyTypeObject *PollFD;
54
55#include "config.h"
56
57#if PYGOBJECT_FLAGS_SIGNED
58typedef gint pyg_flags_type;
59#else
60typedef guint pyg_flags_type;
61#endif
62
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");
70 import_array();
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 {
102 pyg_flags_type flags;
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");
110 pyg_flags_type flags;
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");
135 pyg_flags_type flags;
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
178 bool completed = !PyErr_Occurred();
179
180 if (!completed)
181 PyErr_Print();
182
183 bool valid_result = (completed && PyBool_Check(result));
184
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);
193
194 Py_XDECREF(result);
195
196 PyGILState_Release(gstate);
197
198 if (!valid_result)
199 throw sigrok::Error(SR_ERR);
200
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);
231
232 bool completed = !PyErr_Occurred();
233
234 if (!completed)
235 PyErr_Print();
236
237 bool valid_result = (completed && result == Py_None);
238
239 Py_XDECREF(result);
240
241 if (completed && !valid_result)
242 {
243 PyErr_SetString(PyExc_TypeError,
244 "Log callback did not return None");
245 PyErr_Print();
246 }
247
248 PyGILState_Release(gstate);
249
250 if (!valid_result)
251 throw sigrok::Error(SR_ERR);
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);
285
286 bool completed = !PyErr_Occurred();
287
288 if (!completed)
289 PyErr_Print();
290
291 bool valid_result = (completed && result == Py_None);
292
293 Py_XDECREF(result);
294
295 if (completed && !valid_result)
296 {
297 PyErr_SetString(PyExc_TypeError,
298 "Datafeed callback did not return None");
299 PyErr_Print();
300 }
301
302 PyGILState_Release(gstate);
303
304 if (!valid_result)
305 throw sigrok::Error(SR_ERR);
306 };
307
308 Py_XINCREF($input);
309}
310
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
354%{
355
356#include "libsigrokcxx/libsigrokcxx.hpp"
357
358/* Convert from a Python dict to a std::map<std::string, std::string> */
359std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
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{
385 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
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))
392 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
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
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{
407 GVariantType *type = option->default_value().get_type().gobj();
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))
414 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
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
448%}
449
450/* Ignore these methods, we will override them below. */
451%ignore sigrok::Analog::data;
452%ignore sigrok::Driver::scan;
453%ignore sigrok::InputFormat::create_input;
454%ignore sigrok::OutputFormat::create_output;
455
456%include "doc.i"
457
458%define %attributevector(Class, Type, Name, Get)
459%rename(_ ## Get) sigrok::Class::Get;
460%extend sigrok::Class
461{
462%pythoncode
463{
464 Name = property(_ ## Get)
465}
466}
467%enddef
468
469%define %attributemap(Class, Type, Name, Get)
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}
478%enddef
479
480%define %enumextras(Class)
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}
497%enddef
498
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);
517 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
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
534/* Support InputFormat.create_input() with keyword arguments. */
535%extend sigrok::InputFormat
536{
537 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
538 {
539 return $self->create_input(
540 dict_to_map_options(dict, $self->options()));
541 }
542}
543
544%pythoncode
545{
546 def _InputFormat_create_input(self, **kwargs):
547 return self._create_input(kwargs)
548
549 InputFormat.create_input = _InputFormat_create_input
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 {
558 return $self->create_output(device,
559 dict_to_map_options(dict, $self->options()));
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}
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}