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