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