]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
python: Fix error handling for callbacks.
[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         bool completed = !PyErr_Occurred();
177
178         if (!completed)
179             PyErr_Print();
180
181         bool valid_result = (completed && PyBool_Check(result));
182
183         if (completed && !valid_result)
184         {
185             PyErr_SetString(PyExc_TypeError,
186                 "EventSource callback did not return a boolean");
187             PyErr_Print();
188         }
189
190         bool retval = (valid_result && result == Py_True);
191
192         Py_XDECREF(result);
193
194         PyGILState_Release(gstate);
195
196         if (!valid_result)
197             throw sigrok::Error(SR_ERR);
198
199         return retval;
200     };
201
202     Py_XINCREF($input);
203 }
204
205 /* Map from callable PyObject to LogCallbackFunction */
206 %typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
207     $1 = PyCallable_Check($input);
208 }
209
210 %typemap(in) sigrok::LogCallbackFunction {
211     if (!PyCallable_Check($input))
212         SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
213
214     $1 = [=] (const sigrok::LogLevel *loglevel, string message) {
215         auto gstate = PyGILState_Ensure();
216
217         auto log_obj = SWIG_NewPointerObj(
218                 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
219
220         auto string_obj = PyString_FromString(message.c_str());
221
222         auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
223
224         auto result = PyEval_CallObject($input, arglist);
225
226         Py_XDECREF(arglist);
227         Py_XDECREF(log_obj);
228         Py_XDECREF(string_obj);
229
230         bool completed = !PyErr_Occurred();
231
232         if (!completed)
233             PyErr_Print();
234
235         bool valid_result = (completed && result == Py_None);
236
237         Py_XDECREF(result);
238
239         if (completed && !valid_result)
240         {
241             PyErr_SetString(PyExc_TypeError,
242                 "Log callback did not return None");
243             PyErr_Print();
244         }
245
246         PyGILState_Release(gstate);
247
248         if (!valid_result)
249             throw sigrok::Error(SR_ERR);
250     };
251
252     Py_XINCREF($input);
253 }
254
255 /* Map from callable PyObject to DatafeedCallbackFunction */
256 %typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
257     $1 = PyCallable_Check($input);
258 }
259
260 %typemap(in) sigrok::DatafeedCallbackFunction {
261     if (!PyCallable_Check($input))
262         SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
263
264     $1 = [=] (std::shared_ptr<sigrok::Device> device,
265             std::shared_ptr<sigrok::Packet> packet) {
266         auto gstate = PyGILState_Ensure();
267
268         auto device_obj = SWIG_NewPointerObj(
269             SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
270             SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
271
272         auto packet_obj = SWIG_NewPointerObj(
273             SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
274             SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
275
276         auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
277
278         auto result = PyEval_CallObject($input, arglist);
279
280         Py_XDECREF(arglist);
281         Py_XDECREF(device_obj);
282         Py_XDECREF(packet_obj);
283
284         bool completed = !PyErr_Occurred();
285
286         if (!completed)
287             PyErr_Print();
288
289         bool valid_result = (completed && result == Py_None);
290
291         Py_XDECREF(result);
292
293         if (completed && !valid_result)
294         {
295             PyErr_SetString(PyExc_TypeError,
296                 "Datafeed callback did not return None");
297             PyErr_Print();
298         }
299
300         PyGILState_Release(gstate);
301
302         if (!valid_result)
303             throw sigrok::Error(SR_ERR);
304     };
305
306     Py_XINCREF($input);
307 }
308
309 %{
310
311 #include "libsigrok/libsigrok.hpp"
312
313 /* Convert from a Python dict to a std::map<std::string, std::string> */
314 std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
315 {
316     if (!PyDict_Check(dict))
317         throw sigrok::Error(SR_ERR_ARG);
318
319     std::map<std::string, std::string> output;
320
321     PyObject *py_key, *py_value;
322     Py_ssize_t pos = 0;
323
324     while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
325         if (!PyString_Check(py_key))
326             throw sigrok::Error(SR_ERR_ARG);
327         if (!PyString_Check(py_value))
328             throw sigrok::Error(SR_ERR_ARG);
329         auto key = PyString_AsString(py_key);
330         auto value = PyString_AsString(py_value);
331         output[key] = value;
332     }
333
334     return output;
335 }
336
337 /* Convert from a Python type to Glib::Variant, according to config key data type. */
338 Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
339 {
340     enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
341
342     if (type == SR_T_UINT64 && PyInt_Check(input))
343         return Glib::Variant<guint64>::create(PyInt_AsLong(input));
344     if (type == SR_T_UINT64 && PyLong_Check(input))
345         return Glib::Variant<guint64>::create(PyLong_AsLong(input));
346     else if (type == SR_T_STRING && PyString_Check(input))
347         return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
348     else if (type == SR_T_BOOL && PyBool_Check(input))
349         return Glib::Variant<bool>::create(input == Py_True);
350     else if (type == SR_T_FLOAT && PyFloat_Check(input))
351         return Glib::Variant<double>::create(PyFloat_AsDouble(input));
352     else if (type == SR_T_INT32 && PyInt_Check(input))
353         return Glib::Variant<gint32>::create(PyInt_AsLong(input));
354     else
355         throw sigrok::Error(SR_ERR_ARG);
356 }
357
358 /* Convert from a Python type to Glib::Variant, according to Option data type. */
359 Glib::VariantBase python_to_variant_by_option(PyObject *input,
360     std::shared_ptr<sigrok::Option> option)
361 {
362     GVariantType *type = option->default_value().get_type().gobj();
363
364     if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
365         return Glib::Variant<guint64>::create(PyInt_AsLong(input));
366     if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
367         return Glib::Variant<guint64>::create(PyLong_AsLong(input));
368     else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
369         return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
370     else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
371         return Glib::Variant<bool>::create(input == Py_True);
372     else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
373         return Glib::Variant<double>::create(PyFloat_AsDouble(input));
374     else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
375         return Glib::Variant<gint32>::create(PyInt_AsLong(input));
376     else
377         throw sigrok::Error(SR_ERR_ARG);
378 }
379
380 /* Convert from a Python dict to a std::map<std::string, std::string> */
381 std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
382     std::map<std::string, std::shared_ptr<sigrok::Option> > options)
383 {
384     if (!PyDict_Check(dict))
385         throw sigrok::Error(SR_ERR_ARG);
386
387     std::map<std::string, Glib::VariantBase> output;
388
389     PyObject *py_key, *py_value;
390     Py_ssize_t pos = 0;
391
392     while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
393         if (!PyString_Check(py_key))
394             throw sigrok::Error(SR_ERR_ARG);
395         auto key = PyString_AsString(py_key);
396         auto value = python_to_variant_by_option(py_value, options[key]);
397         output[key] = value;
398     }
399
400     return output;
401 }
402
403 %}
404
405 /* Ignore these methods, we will override them below. */
406 %ignore sigrok::Driver::scan;
407 %ignore sigrok::InputFormat::create_input;
408 %ignore sigrok::OutputFormat::create_output;
409
410 %include "doc.i"
411
412 %define %attributevector(Class, Type, Name, Get)
413 %rename(_ ## Get) sigrok::Class::Get;
414 %extend sigrok::Class
415 {
416 %pythoncode
417 {
418   Name = property(_ ## Get)
419 }
420 }
421 %enddef
422
423 %define %attributemap(Class, Type, Name, Get)
424 %rename(_ ## Get) sigrok::Class::Get;
425 %extend sigrok::Class
426 {
427 %pythoncode
428 {
429   Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
430 }
431 }
432 %enddef
433
434 %define %enumextras(Class)
435 %extend sigrok::Class
436 {
437   long __hash__()
438   {
439     return (long) $self;
440   }
441
442 %pythoncode
443 {
444   def __eq__(self, other):
445     return (type(self) is type(other) and hash(self) == hash(other))
446
447   def __ne__(self, other):
448     return (type(self) is not type(other) or hash(self) != hash(other))
449 }
450 }
451 %enddef
452
453 %include "../../../swig/classes.i"
454
455 /* Support Driver.scan() with keyword arguments. */
456 %extend sigrok::Driver
457 {
458     std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
459     {
460         if (!PyDict_Check(dict))
461             throw sigrok::Error(SR_ERR_ARG);
462
463         PyObject *py_key, *py_value;
464         Py_ssize_t pos = 0;
465         std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
466
467         while (PyDict_Next(dict, &pos, &py_key, &py_value))
468         {
469             if (!PyString_Check(py_key))
470                 throw sigrok::Error(SR_ERR_ARG);
471             auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
472             auto value = python_to_variant_by_key(py_value, key);
473             options[key] = value;
474         }
475
476         return $self->scan(options);
477     }
478 }
479
480 %pythoncode
481 {
482     def _Driver_scan(self, **kwargs):
483         return self._scan_kwargs(kwargs)
484
485     Driver.scan = _Driver_scan
486 }
487
488 /* Support InputFormat.create_input() with keyword arguments. */
489 %extend sigrok::InputFormat
490 {
491     std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
492     {
493         return $self->create_input(
494             dict_to_map_options(dict, $self->options()));
495     }
496 }
497
498 %pythoncode
499 {
500     def _InputFormat_create_input(self, **kwargs):
501         return self._create_input(kwargs)
502
503     InputFormat.create_input = _InputFormat_create_input
504 }
505
506 /* Support OutputFormat.create_output() with keyword arguments. */
507 %extend sigrok::OutputFormat
508 {
509     std::shared_ptr<sigrok::Output> _create_output_kwargs(
510         std::shared_ptr<sigrok::Device> device, PyObject *dict)
511     {
512         return $self->create_output(device,
513             dict_to_map_options(dict, $self->options()));
514     }
515 }
516
517 %pythoncode
518 {
519     def _OutputFormat_create_output(self, device, **kwargs):
520         return self._create_output_kwargs(device, kwargs)
521
522     OutputFormat.create_output = _OutputFormat_create_output
523 }
524
525 /* Support config_set() with Python input types. */
526 %extend sigrok::Configurable
527 {
528     void config_set(const ConfigKey *key, PyObject *input)
529     {
530         $self->config_set(key, python_to_variant_by_key(input, key));
531     }
532 }