]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
cxx: Implement more of EnumValue in template.
[libsigrok.git] / bindings / python / sigrok / core / classes.i
CommitLineData
f7740954
ML
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
6a8c1d68
ML
20%define DOCSTRING
21"@mainpage API Reference
22
23Introduction
24------------
25
26The pysigrok API provides an object-oriented Python interface to the
27functionality in libsigrok. It is built on top of the sigrok++ C++ API.
28
29Getting started
30---------------
31
32Usage of the pysigrok API needs to begin with a call to Context.create().
33This will create the global libsigrok context and returns a Context object.
34Methods on this object provide access to the hardware drivers, input and output
35formats supported by the library, as well as means of creating other objects
36such as sessions and triggers.
37
38Error handling
39--------------
40
41When any libsigrok C API call returns an error, an Error exception is raised,
42which provides access to the error code and description."
43%enddef
44
45%module(docstring=DOCSTRING) classes
f7740954
ML
46
47%{
48#include <pygobject.h>
49
50PyObject *GLib;
51PyTypeObject *IOChannel;
52PyTypeObject *PollFD;
53
0e1a7fe9 54#include "config.h"
abc7146d
ML
55
56#if PYGOBJECT_FLAGS_SIGNED
57typedef gint pyg_flags_type;
58#else
59typedef guint pyg_flags_type;
60#endif
61
f7740954
ML
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 {
abc7146d 100 pyg_flags_type flags;
f7740954
ML
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");
abc7146d 108 pyg_flags_type flags;
f7740954
ML
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");
abc7146d 133 pyg_flags_type flags;
f7740954
ML
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> */
58aa1f83 264std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
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. */
288Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
289{
9d229ecb 290 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
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))
f90ed2d1 297 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
f7740954
ML
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
58aa1f83
ML
308/* Convert from a Python type to Glib::Variant, according to Option data type. */
309Glib::VariantBase python_to_variant_by_option(PyObject *input,
310 std::shared_ptr<sigrok::Option> option)
311{
3b161085 312 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
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))
f90ed2d1 319 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
58aa1f83
ML
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> */
331std::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
f7740954
ML
353%}
354
355/* Ignore these methods, we will override them below. */
356%ignore sigrok::Driver::scan;
ca3291e3 357%ignore sigrok::InputFormat::create_input;
f7740954
ML
358%ignore sigrok::OutputFormat::create_output;
359
bd4fda24
ML
360%include "doc.i"
361
f7740954
ML
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
ca3291e3 397/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
398%extend sigrok::InputFormat
399{
ca3291e3 400 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 401 {
ca3291e3 402 return $self->create_input(
3b161085 403 dict_to_map_options(dict, $self->options()));
f7740954
ML
404 }
405}
406
407%pythoncode
408{
ca3291e3
ML
409 def _InputFormat_create_input(self, **kwargs):
410 return self._create_input(kwargs)
f7740954 411
ca3291e3 412 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
413}
414
415/* Support OutputFormat.create_output() with keyword arguments. */
416%extend sigrok::OutputFormat
417{
418 std::shared_ptr<sigrok::Output> _create_output_kwargs(
419 std::shared_ptr<sigrok::Device> device, PyObject *dict)
420 {
58aa1f83 421 return $self->create_output(device,
3b161085 422 dict_to_map_options(dict, $self->options()));
f7740954
ML
423 }
424}
425
426%pythoncode
427{
428 def _OutputFormat_create_output(self, device, **kwargs):
429 return self._create_output_kwargs(device, kwargs)
430
431 OutputFormat.create_output = _OutputFormat_create_output
432}
433
434/* Support config_set() with Python input types. */
435%extend sigrok::Configurable
436{
437 void config_set(const ConfigKey *key, PyObject *input)
438 {
439 $self->config_set(key, python_to_variant_by_key(input, key));
440 }
441}