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