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