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