]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
python: Give all enum values __doc__ strings.
[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 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
51 #include <numpy/arrayobject.h>
52
53 PyObject *PyGObject_lib;
54 PyObject *GLib;
55
56 #include "config.h"
57
58 #if PYGOBJECT_FLAGS_SIGNED
59 typedef gint pyg_flags_type;
60 #else
61 typedef 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> */
290 std::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. */
314 Glib::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. */
335 Glib::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> */
357 std::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_start.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 }
530
531 %include "doc_end.i"