]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
bindings: Transfer C++ documentation strings to Python and Java wrappers.
[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 %module classes
21
22 %{
23 #include <pygobject.h>
24
25 PyObject *GLib;
26 PyTypeObject *IOChannel;
27 PyTypeObject *PollFD;
28
29 #include "../../../../config.h"
30
31 #if PYGOBJECT_FLAGS_SIGNED
32 typedef gint pyg_flags_type;
33 #else
34 typedef guint pyg_flags_type;
35 #endif
36
37 %}
38
39 %init %{
40     pygobject_init(-1, -1, -1);
41     GLib = PyImport_ImportModule("gi.repository.GLib");
42     IOChannel = (PyTypeObject *) PyObject_GetAttrString(GLib, "IOChannel");
43     PollFD = (PyTypeObject *) PyObject_GetAttrString(GLib, "PollFD");
44 %}
45
46 /* Map file objects to file descriptors. */
47 %typecheck(SWIG_TYPECHECK_POINTER) int fd {
48     $1 = (PyObject_AsFileDescriptor($input) != -1);
49 }
50
51 %typemap(in) int fd {
52     int fd = PyObject_AsFileDescriptor($input);
53     if (fd == -1)
54         SWIG_exception(SWIG_TypeError,
55             "Expected file object or integer file descriptor");
56     else
57       $1 = fd;
58 }
59
60 /* Map from Glib::Variant to native Python types. */
61 %typemap(out) Glib::VariantBase {
62     GValue *value = g_new0(GValue, 1);
63     g_value_init(value, G_TYPE_VARIANT);
64     g_value_set_variant(value, $1.gobj());
65     PyObject *variant = pyg_value_as_pyobject(value, true);
66     $result = PyObject_CallMethod(variant,
67         const_cast<char *>("unpack"),
68         const_cast<char *>(""), NULL);
69     Py_XDECREF(variant);
70     g_free(value);
71 }
72
73 /* Map from Glib::IOCondition to GLib.IOCondition. */
74 %typecheck(SWIG_TYPECHECK_POINTER) Glib::IOCondition {
75     pyg_flags_type flags;
76     $1 = pygobject_check($input, &PyGFlags_Type) &&
77          (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) != -1);
78 }
79
80 %typemap(in) Glib::IOCondition {
81     if (!pygobject_check($input, &PyGFlags_Type))
82         SWIG_exception(SWIG_TypeError, "Expected GLib.IOCondition value");
83     pyg_flags_type flags;
84     if (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) == -1)
85         SWIG_exception(SWIG_TypeError, "Not a valid Glib.IOCondition value");
86     $1 = (Glib::IOCondition) flags;
87 }
88
89 /* And back */
90 %typemap(out) Glib::IOCondition {
91     GValue *value = g_new0(GValue, 1);
92     g_value_init(value, G_TYPE_IO_CONDITION);
93     g_value_set_flags(value, &$1);
94     $result = pyg_value_as_pyobject(value, true);
95     g_free(value);
96 }
97
98 /* Map from GLib.PollFD to Glib::PollFD *. */
99 %typecheck(SWIG_TYPECHECK_POINTER) Glib::PollFD {
100     $1 = pygobject_check($input, PollFD);
101 }
102
103 %typemap(in) Glib::PollFD {
104     if (!pygobject_check($input, PollFD))
105         SWIG_exception(SWIG_TypeError, "Expected GLib.PollFD");
106     PyObject *fd_obj = PyObject_GetAttrString($input, "fd");
107     PyObject *events_obj = PyObject_GetAttrString($input, "events");
108     pyg_flags_type flags;
109     pyg_flags_get_value(G_TYPE_IO_CONDITION, events_obj, &flags);
110     int fd = PyInt_AsLong(fd_obj);
111     Glib::IOCondition events = (Glib::IOCondition) flags;
112     $1 = Glib::PollFD(fd, events);
113 }
114
115 /* Map from GLib.IOChannel to Glib::IOChannel *. */
116 %typecheck(SWIG_TYPECHECK_POINTER) Glib::RefPtr<Glib::IOChannel> {
117     $1 = pygobject_check($input, IOChannel);
118 }
119
120 %typemap(in) Glib::RefPtr<Glib::IOChannel> {
121     if (!pygobject_check($input, IOChannel))
122         SWIG_exception(SWIG_TypeError, "Expected GLib.IOChannel");
123     $1 = Glib::wrap((GIOChannel *) PyObject_Hash($input), true);
124 }
125
126 /* Map from callable PyObject to SourceCallbackFunction. */
127 %typecheck(SWIG_TYPECHECK_POINTER) sigrok::SourceCallbackFunction {
128     $1 = PyCallable_Check($input);
129 }
130
131 %typemap(in) sigrok::SourceCallbackFunction {
132     if (!PyCallable_Check($input))
133         SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
134
135     $1 = [=] (Glib::IOCondition revents) {
136         auto gstate = PyGILState_Ensure();
137
138         GValue *value = g_new0(GValue, 1);
139         g_value_init(value, G_TYPE_IO_CONDITION);
140         g_value_set_flags(value, revents);
141         auto revents_obj = pyg_value_as_pyobject(value, true);
142         g_free(value);
143
144         auto arglist = Py_BuildValue("(O)", revents_obj);
145
146         auto result = PyEval_CallObject($input, arglist);
147
148         Py_XDECREF(arglist);
149         Py_XDECREF(revents_obj);
150
151         if (PyErr_Occurred() || !PyBool_Check(result))
152             throw sigrok::Error(SR_ERR);
153
154         bool retval = (result == Py_True);
155
156         Py_XDECREF(result);
157
158         PyGILState_Release(gstate);
159
160         return retval;
161     };
162
163     Py_XINCREF($input);
164 }
165
166 /* Map from callable PyObject to LogCallbackFunction */
167 %typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
168     $1 = PyCallable_Check($input);
169 }
170
171 %typemap(in) sigrok::LogCallbackFunction {
172     if (!PyCallable_Check($input))
173         SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
174
175     $1 = [=] (const sigrok::LogLevel *loglevel, string message) {
176         auto gstate = PyGILState_Ensure();
177
178         auto log_obj = SWIG_NewPointerObj(
179                 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
180
181         auto string_obj = PyString_FromString(message.c_str());
182
183         auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
184
185         auto result = PyEval_CallObject($input, arglist);
186
187         Py_XDECREF(arglist);
188         Py_XDECREF(log_obj);
189         Py_XDECREF(string_obj);
190         Py_XDECREF(result);
191
192         PyGILState_Release(gstate);
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         Py_XDECREF(result);
227
228         PyGILState_Release(gstate);
229     };
230
231     Py_XINCREF($input);
232 }
233
234 %{
235
236 #include "libsigrok/libsigrok.hpp"
237
238 /* Convert from a Python dict to a std::map<std::string, std::string> */
239 std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
240 {
241     if (!PyDict_Check(dict))
242         throw sigrok::Error(SR_ERR_ARG);
243
244     std::map<std::string, std::string> output;
245
246     PyObject *py_key, *py_value;
247     Py_ssize_t pos = 0;
248
249     while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
250         if (!PyString_Check(py_key))
251             throw sigrok::Error(SR_ERR_ARG);
252         if (!PyString_Check(py_value))
253             throw sigrok::Error(SR_ERR_ARG);
254         auto key = PyString_AsString(py_key);
255         auto value = PyString_AsString(py_value);
256         output[key] = value;
257     }
258
259     return output;
260 }
261
262 /* Convert from a Python type to Glib::Variant, according to config key data type. */
263 Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
264 {
265     enum sr_datatype type = key->get_data_type()->get_id();
266
267     if (type == SR_T_UINT64 && PyInt_Check(input))
268         return Glib::Variant<guint64>::create(PyInt_AsLong(input));
269     if (type == SR_T_UINT64 && PyLong_Check(input))
270         return Glib::Variant<guint64>::create(PyLong_AsLong(input));
271     else if (type == SR_T_STRING && PyString_Check(input))
272         return Glib::Variant<std::string>::create(PyString_AsString(input));
273     else if (type == SR_T_BOOL && PyBool_Check(input))
274         return Glib::Variant<bool>::create(input == Py_True);
275     else if (type == SR_T_FLOAT && PyFloat_Check(input))
276         return Glib::Variant<double>::create(PyFloat_AsDouble(input));
277     else if (type == SR_T_INT32 && PyInt_Check(input))
278         return Glib::Variant<gint32>::create(PyInt_AsLong(input));
279     else
280         throw sigrok::Error(SR_ERR_ARG);
281 }
282
283 /* Convert from a Python type to Glib::Variant, according to Option data type. */
284 Glib::VariantBase python_to_variant_by_option(PyObject *input,
285     std::shared_ptr<sigrok::Option> option)
286 {
287     GVariantType *type = option->get_default_value().get_type().gobj();
288
289     if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
290         return Glib::Variant<guint64>::create(PyInt_AsLong(input));
291     if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
292         return Glib::Variant<guint64>::create(PyLong_AsLong(input));
293     else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
294         return Glib::Variant<std::string>::create(PyString_AsString(input));
295     else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
296         return Glib::Variant<bool>::create(input == Py_True);
297     else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
298         return Glib::Variant<double>::create(PyFloat_AsDouble(input));
299     else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
300         return Glib::Variant<gint32>::create(PyInt_AsLong(input));
301     else
302         throw sigrok::Error(SR_ERR_ARG);
303 }
304
305 /* Convert from a Python dict to a std::map<std::string, std::string> */
306 std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
307     std::map<std::string, std::shared_ptr<sigrok::Option> > options)
308 {
309     if (!PyDict_Check(dict))
310         throw sigrok::Error(SR_ERR_ARG);
311
312     std::map<std::string, Glib::VariantBase> output;
313
314     PyObject *py_key, *py_value;
315     Py_ssize_t pos = 0;
316
317     while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
318         if (!PyString_Check(py_key))
319             throw sigrok::Error(SR_ERR_ARG);
320         auto key = PyString_AsString(py_key);
321         auto value = python_to_variant_by_option(py_value, options[key]);
322         output[key] = value;
323     }
324
325     return output;
326 }
327
328 %}
329
330 /* Ignore these methods, we will override them below. */
331 %ignore sigrok::Driver::scan;
332 %ignore sigrok::InputFormat::open_file;
333 %ignore sigrok::OutputFormat::create_output;
334
335 %include "doc.i"
336
337 %include "../../../swig/classes.i"
338
339 /* Support Driver.scan() with keyword arguments. */
340 %extend sigrok::Driver
341 {
342     std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
343     {
344         if (!PyDict_Check(dict))
345             throw sigrok::Error(SR_ERR_ARG);
346
347         PyObject *py_key, *py_value;
348         Py_ssize_t pos = 0;
349         std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
350
351         while (PyDict_Next(dict, &pos, &py_key, &py_value))
352         {
353             if (!PyString_Check(py_key))
354                 throw sigrok::Error(SR_ERR_ARG);
355             auto key = sigrok::ConfigKey::get(PyString_AsString(py_key));
356             auto value = python_to_variant_by_key(py_value, key);
357             options[key] = value;
358         }
359
360         return $self->scan(options);
361     }
362 }
363
364 %pythoncode
365 {
366     def _Driver_scan(self, **kwargs):
367         return self._scan_kwargs(kwargs)
368
369     Driver.scan = _Driver_scan
370 }
371
372 /* Support InputFormat.open_file() with keyword arguments. */
373 %extend sigrok::InputFormat
374 {
375     std::shared_ptr<sigrok::InputFileDevice> _open_file_kwargs(std::string filename, PyObject *dict)
376     {
377         return $self->open_file(filename, dict_to_map_string(dict));
378     }
379 }
380
381 %pythoncode
382 {
383     def _InputFormat_open_file(self, filename, **kwargs):
384         return self._open_file_kwargs(filename, kwargs)
385
386     InputFormat.open_file = _InputFormat_open_file
387 }
388
389 /* Support OutputFormat.create_output() with keyword arguments. */
390 %extend sigrok::OutputFormat
391 {
392     std::shared_ptr<sigrok::Output> _create_output_kwargs(
393         std::shared_ptr<sigrok::Device> device, PyObject *dict)
394     {
395         return $self->create_output(device,
396             dict_to_map_options(dict, $self->get_options()));
397     }
398 }
399
400 %pythoncode
401 {
402     def _OutputFormat_create_output(self, device, **kwargs):
403         return self._create_output_kwargs(device, kwargs)
404
405     OutputFormat.create_output = _OutputFormat_create_output
406 }
407
408 /* Support config_set() with Python input types. */
409 %extend sigrok::Configurable
410 {
411     void config_set(const ConfigKey *key, PyObject *input)
412     {
413         $self->config_set(key, python_to_variant_by_key(input, key));
414     }
415 }