]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
01201bd3d7e9ae5a63f2369595eb79c334f1d0f0
[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 #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> */
300 std::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. */
324 Glib::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. */
345 Glib::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> */
367 std::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::Driver::scan;
394 %ignore sigrok::InputFormat::create_input;
395 %ignore sigrok::OutputFormat::create_output;
396
397 %include "doc_start.i"
398
399 %define %attributevector(Class, Type, Name, Get)
400 %rename(_ ## Get) sigrok::Class::Get;
401 %extend sigrok::Class
402 {
403 %pythoncode
404 {
405   Name = property(_ ## Get)
406 }
407 }
408 %enddef
409
410 %define %attributemap(Class, Type, Name, Get)
411 %rename(_ ## Get) sigrok::Class::Get;
412 %extend sigrok::Class
413 {
414 %pythoncode
415 {
416   Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
417 }
418 }
419 %enddef
420
421 %define %enumextras(Class)
422 %extend sigrok::Class
423 {
424   long __hash__()
425   {
426     return (long) $self;
427   }
428
429 %pythoncode
430 {
431   def __eq__(self, other):
432     return (type(self) is type(other) and hash(self) == hash(other))
433
434   def __ne__(self, other):
435     return (type(self) is not type(other) or hash(self) != hash(other))
436 }
437 }
438 %enddef
439
440 %include "../../../swig/classes.i"
441
442 /* Support Driver.scan() with keyword arguments. */
443 %extend sigrok::Driver
444 {
445     std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
446     {
447         if (!PyDict_Check(dict))
448             throw sigrok::Error(SR_ERR_ARG);
449
450         PyObject *py_key, *py_value;
451         Py_ssize_t pos = 0;
452         std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
453
454         while (PyDict_Next(dict, &pos, &py_key, &py_value))
455         {
456             if (!string_check(py_key))
457                 throw sigrok::Error(SR_ERR_ARG);
458             auto key = sigrok::ConfigKey::get_by_identifier(string_from_python(py_key));
459             auto value = python_to_variant_by_key(py_value, key);
460             options[key] = value;
461         }
462
463         return $self->scan(options);
464     }
465 }
466
467 %pythoncode
468 {
469     def _Driver_scan(self, **kwargs):
470         return self._scan_kwargs(kwargs)
471
472     Driver.scan = _Driver_scan
473 }
474
475 /* Support InputFormat.create_input() with keyword arguments. */
476 %extend sigrok::InputFormat
477 {
478     std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
479     {
480         return $self->create_input(
481             dict_to_map_options(dict, $self->options()));
482     }
483 }
484
485 %pythoncode
486 {
487     def _InputFormat_create_input(self, **kwargs):
488         return self._create_input(kwargs)
489
490     InputFormat.create_input = _InputFormat_create_input
491 }
492
493 /* Support OutputFormat.create_output() with keyword arguments. */
494 %extend sigrok::OutputFormat
495 {
496     std::shared_ptr<sigrok::Output> _create_output_kwargs(
497         std::shared_ptr<sigrok::Device> device, PyObject *dict)
498     {
499         return $self->create_output(device,
500             dict_to_map_options(dict, $self->options()));
501     }
502 }
503
504 %pythoncode
505 {
506     def _OutputFormat_create_output(self, device, **kwargs):
507         return self._create_output_kwargs(device, kwargs)
508
509     OutputFormat.create_output = _OutputFormat_create_output
510 }
511
512 /* Support config_set() with Python input types. */
513 %extend sigrok::Configurable
514 {
515     void config_set(const ConfigKey *key, PyObject *input)
516     {
517         $self->config_set(key, python_to_variant_by_key(input, key));
518     }
519 }
520
521 /* Return NumPy array from Analog::data(). */
522 %extend sigrok::Analog
523 {
524     PyObject * _data()
525     {
526         int nd = 2;
527         npy_intp dims[2];
528         dims[0] = $self->channels().size();
529         dims[1] = $self->num_samples();
530         int typenum = NPY_FLOAT;
531         void *data = $self->data_pointer();
532         return PyArray_SimpleNewFromData(nd, dims, typenum, data);
533     }
534
535 %pythoncode
536 {
537     data = property(_data)
538 }
539 }
540
541 %include "doc_end.i"