]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
python: Fix the build for Python >= 3.
[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 #include <numpy/arrayobject.h>
51
52 PyObject *PyGObject_lib;
53 PyObject *GLib;
54 PyTypeObject *IOChannel;
55 PyTypeObject *PollFD;
56
57 #include "config.h"
58
59 #if PYGOBJECT_FLAGS_SIGNED
60 typedef gint pyg_flags_type;
61 #else
62 typedef guint pyg_flags_type;
63 #endif
64
65 %}
66
67 %init %{
68     PyGObject_lib = pygobject_init(-1, -1, -1);
69     if (!PyGObject_lib)
70         fprintf(stderr, "pygobject initialization failed.\n");
71     GLib = PyImport_ImportModule("gi.repository.GLib");
72     /*
73      * This check can't save us if the import fails, but at least it gives us
74      * a starting point to trace the issue versus straight out crashing.
75      */
76     if (!GLib) {
77         fprintf(stderr, "Import of gi.repository.GLib failed.\n");
78 #if PY_VERSION_HEX >= 0x03000000
79         return NULL;
80 #else
81         return;
82 #endif
83     }
84     IOChannel = (PyTypeObject *) PyObject_GetAttrString(GLib, "IOChannel");
85     PollFD = (PyTypeObject *) PyObject_GetAttrString(GLib, "PollFD");
86     import_array();
87 %}
88
89 /* Map file objects to file descriptors. */
90 %typecheck(SWIG_TYPECHECK_POINTER) int fd {
91     $1 = (PyObject_AsFileDescriptor($input) != -1);
92 }
93
94 %typemap(in) int fd {
95     int fd = PyObject_AsFileDescriptor($input);
96     if (fd == -1)
97         SWIG_exception(SWIG_TypeError,
98             "Expected file object or integer file descriptor");
99     else
100       $1 = fd;
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"),
111         const_cast<char *>(""), NULL);
112     Py_XDECREF(variant);
113     g_free(value);
114 }
115
116 /* Map from Glib::IOCondition to GLib.IOCondition. */
117 %typecheck(SWIG_TYPECHECK_POINTER) Glib::IOCondition {
118     pyg_flags_type flags;
119     $1 = pygobject_check($input, &PyGFlags_Type) &&
120          (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) != -1);
121 }
122
123 %typemap(in) Glib::IOCondition {
124     if (!pygobject_check($input, &PyGFlags_Type))
125         SWIG_exception(SWIG_TypeError, "Expected GLib.IOCondition value");
126     pyg_flags_type flags;
127     if (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) == -1)
128         SWIG_exception(SWIG_TypeError, "Not a valid Glib.IOCondition value");
129     $1 = (Glib::IOCondition) flags;
130 }
131
132 /* And back */
133 %typemap(out) Glib::IOCondition {
134     GValue *value = g_new0(GValue, 1);
135     g_value_init(value, G_TYPE_IO_CONDITION);
136     g_value_set_flags(value, &$1);
137     $result = pyg_value_as_pyobject(value, true);
138     g_free(value);
139 }
140
141 /* Map from GLib.PollFD to Glib::PollFD *. */
142 %typecheck(SWIG_TYPECHECK_POINTER) Glib::PollFD {
143     $1 = pygobject_check($input, PollFD);
144 }
145
146 %typemap(in) Glib::PollFD {
147     if (!pygobject_check($input, PollFD))
148         SWIG_exception(SWIG_TypeError, "Expected GLib.PollFD");
149     PyObject *fd_obj = PyObject_GetAttrString($input, "fd");
150     PyObject *events_obj = PyObject_GetAttrString($input, "events");
151     pyg_flags_type flags;
152     pyg_flags_get_value(G_TYPE_IO_CONDITION, events_obj, &flags);
153     int fd = PyInt_AsLong(fd_obj);
154     Glib::IOCondition events = (Glib::IOCondition) flags;
155     $1 = Glib::PollFD(fd, events);
156 }
157
158 /* Map from GLib.IOChannel to Glib::IOChannel *. */
159 %typecheck(SWIG_TYPECHECK_POINTER) Glib::RefPtr<Glib::IOChannel> {
160     $1 = pygobject_check($input, IOChannel);
161 }
162
163 %typemap(in) Glib::RefPtr<Glib::IOChannel> {
164     if (!pygobject_check($input, IOChannel))
165         SWIG_exception(SWIG_TypeError, "Expected GLib.IOChannel");
166     $1 = Glib::wrap((GIOChannel *) PyObject_Hash($input), true);
167 }
168
169 /* Map from callable PyObject to SourceCallbackFunction. */
170 %typecheck(SWIG_TYPECHECK_POINTER) sigrok::SourceCallbackFunction {
171     $1 = PyCallable_Check($input);
172 }
173
174 %typemap(in) sigrok::SourceCallbackFunction {
175     if (!PyCallable_Check($input))
176         SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
177
178     $1 = [=] (Glib::IOCondition revents) {
179         auto gstate = PyGILState_Ensure();
180
181         GValue *value = g_new0(GValue, 1);
182         g_value_init(value, G_TYPE_IO_CONDITION);
183         g_value_set_flags(value, revents);
184         auto revents_obj = pyg_value_as_pyobject(value, true);
185         g_free(value);
186
187         auto arglist = Py_BuildValue("(O)", revents_obj);
188
189         auto result = PyEval_CallObject($input, arglist);
190
191         Py_XDECREF(arglist);
192         Py_XDECREF(revents_obj);
193
194         bool completed = !PyErr_Occurred();
195
196         if (!completed)
197             PyErr_Print();
198
199         bool valid_result = (completed && PyBool_Check(result));
200
201         if (completed && !valid_result)
202         {
203             PyErr_SetString(PyExc_TypeError,
204                 "EventSource callback did not return a boolean");
205             PyErr_Print();
206         }
207
208         bool retval = (valid_result && result == Py_True);
209
210         Py_XDECREF(result);
211
212         PyGILState_Release(gstate);
213
214         if (!valid_result)
215             throw sigrok::Error(SR_ERR);
216
217         return retval;
218     };
219
220     Py_XINCREF($input);
221 }
222
223 /* Map from callable PyObject to LogCallbackFunction */
224 %typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
225     $1 = PyCallable_Check($input);
226 }
227
228 %typemap(in) sigrok::LogCallbackFunction {
229     if (!PyCallable_Check($input))
230         SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
231
232     $1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
233         auto gstate = PyGILState_Ensure();
234
235         auto log_obj = SWIG_NewPointerObj(
236                 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
237
238         auto string_obj = PyString_FromString(message.c_str());
239
240         auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
241
242         auto result = PyEval_CallObject($input, arglist);
243
244         Py_XDECREF(arglist);
245         Py_XDECREF(log_obj);
246         Py_XDECREF(string_obj);
247
248         bool completed = !PyErr_Occurred();
249
250         if (!completed)
251             PyErr_Print();
252
253         bool valid_result = (completed && result == Py_None);
254
255         Py_XDECREF(result);
256
257         if (completed && !valid_result)
258         {
259             PyErr_SetString(PyExc_TypeError,
260                 "Log callback did not return None");
261             PyErr_Print();
262         }
263
264         PyGILState_Release(gstate);
265
266         if (!valid_result)
267             throw sigrok::Error(SR_ERR);
268     };
269
270     Py_XINCREF($input);
271 }
272
273 /* Map from callable PyObject to DatafeedCallbackFunction */
274 %typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
275     $1 = PyCallable_Check($input);
276 }
277
278 %typemap(in) sigrok::DatafeedCallbackFunction {
279     if (!PyCallable_Check($input))
280         SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
281
282     $1 = [=] (std::shared_ptr<sigrok::Device> device,
283             std::shared_ptr<sigrok::Packet> packet) {
284         auto gstate = PyGILState_Ensure();
285
286         auto device_obj = SWIG_NewPointerObj(
287             SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
288             SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
289
290         auto packet_obj = SWIG_NewPointerObj(
291             SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
292             SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
293
294         auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
295
296         auto result = PyEval_CallObject($input, arglist);
297
298         Py_XDECREF(arglist);
299         Py_XDECREF(device_obj);
300         Py_XDECREF(packet_obj);
301
302         bool completed = !PyErr_Occurred();
303
304         if (!completed)
305             PyErr_Print();
306
307         bool valid_result = (completed && result == Py_None);
308
309         Py_XDECREF(result);
310
311         if (completed && !valid_result)
312         {
313             PyErr_SetString(PyExc_TypeError,
314                 "Datafeed callback did not return None");
315             PyErr_Print();
316         }
317
318         PyGILState_Release(gstate);
319
320         if (!valid_result)
321             throw sigrok::Error(SR_ERR);
322     };
323
324     Py_XINCREF($input);
325 }
326
327 /* Cast PacketPayload pointers to correct subclass type. */
328 %ignore sigrok::Packet::payload;
329
330 %extend sigrok::Packet
331 {
332     std::shared_ptr<sigrok::Header> _payload_header()
333     {
334         return dynamic_pointer_cast<sigrok::Header>($self->payload());
335     }
336     std::shared_ptr<sigrok::Meta> _payload_meta()
337     {
338         return dynamic_pointer_cast<sigrok::Meta>($self->payload());
339     }
340     std::shared_ptr<sigrok::Analog> _payload_analog()
341     {
342         return dynamic_pointer_cast<sigrok::Analog>($self->payload());
343     }
344     std::shared_ptr<sigrok::Logic> _payload_logic()
345     {
346         return dynamic_pointer_cast<sigrok::Logic>($self->payload());
347     }
348 }
349
350 %extend sigrok::Packet
351 {
352 %pythoncode
353 {
354     def _payload(self):
355         if self.type == PacketType.HEADER:
356             return self._payload_header()
357         elif self.type == PacketType.META:
358             return self._payload_meta()
359         elif self.type == PacketType.LOGIC:
360             return self._payload_logic()
361         elif self.type == PacketType.ANALOG:
362             return self._payload_analog()
363         else:
364             return None
365
366     payload = property(_payload)
367 }
368 }
369
370 %{
371
372 #include "libsigrokcxx/libsigrokcxx.hpp"
373
374 /* Convert from a Python dict to a std::map<std::string, std::string> */
375 std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
376 {
377     if (!PyDict_Check(dict))
378         throw sigrok::Error(SR_ERR_ARG);
379
380     std::map<std::string, std::string> output;
381
382     PyObject *py_key, *py_value;
383     Py_ssize_t pos = 0;
384
385     while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
386         if (!PyString_Check(py_key))
387             throw sigrok::Error(SR_ERR_ARG);
388         if (!PyString_Check(py_value))
389             throw sigrok::Error(SR_ERR_ARG);
390         auto key = PyString_AsString(py_key);
391         auto value = PyString_AsString(py_value);
392         output[key] = value;
393     }
394
395     return output;
396 }
397
398 /* Convert from a Python type to Glib::Variant, according to config key data type. */
399 Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
400 {
401     enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
402
403     if (type == SR_T_UINT64 && PyInt_Check(input))
404         return Glib::Variant<guint64>::create(PyInt_AsLong(input));
405     if (type == SR_T_UINT64 && PyLong_Check(input))
406         return Glib::Variant<guint64>::create(PyLong_AsLong(input));
407     else if (type == SR_T_STRING && PyString_Check(input))
408         return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
409     else if (type == SR_T_BOOL && PyBool_Check(input))
410         return Glib::Variant<bool>::create(input == Py_True);
411     else if (type == SR_T_FLOAT && PyFloat_Check(input))
412         return Glib::Variant<double>::create(PyFloat_AsDouble(input));
413     else if (type == SR_T_INT32 && PyInt_Check(input))
414         return Glib::Variant<gint32>::create(PyInt_AsLong(input));
415     else
416         throw sigrok::Error(SR_ERR_ARG);
417 }
418
419 /* Convert from a Python type to Glib::Variant, according to Option data type. */
420 Glib::VariantBase python_to_variant_by_option(PyObject *input,
421     std::shared_ptr<sigrok::Option> option)
422 {
423     GVariantType *type = option->default_value().get_type().gobj();
424
425     if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
426         return Glib::Variant<guint64>::create(PyInt_AsLong(input));
427     if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
428         return Glib::Variant<guint64>::create(PyLong_AsLong(input));
429     else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
430         return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
431     else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
432         return Glib::Variant<bool>::create(input == Py_True);
433     else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
434         return Glib::Variant<double>::create(PyFloat_AsDouble(input));
435     else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
436         return Glib::Variant<gint32>::create(PyInt_AsLong(input));
437     else
438         throw sigrok::Error(SR_ERR_ARG);
439 }
440
441 /* Convert from a Python dict to a std::map<std::string, std::string> */
442 std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
443     std::map<std::string, std::shared_ptr<sigrok::Option> > options)
444 {
445     if (!PyDict_Check(dict))
446         throw sigrok::Error(SR_ERR_ARG);
447
448     std::map<std::string, Glib::VariantBase> output;
449
450     PyObject *py_key, *py_value;
451     Py_ssize_t pos = 0;
452
453     while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
454         if (!PyString_Check(py_key))
455             throw sigrok::Error(SR_ERR_ARG);
456         auto key = PyString_AsString(py_key);
457         auto value = python_to_variant_by_option(py_value, options[key]);
458         output[key] = value;
459     }
460
461     return output;
462 }
463
464 %}
465
466 /* Ignore these methods, we will override them below. */
467 %ignore sigrok::Analog::data;
468 %ignore sigrok::Driver::scan;
469 %ignore sigrok::InputFormat::create_input;
470 %ignore sigrok::OutputFormat::create_output;
471
472 %include "doc.i"
473
474 %define %attributevector(Class, Type, Name, Get)
475 %rename(_ ## Get) sigrok::Class::Get;
476 %extend sigrok::Class
477 {
478 %pythoncode
479 {
480   Name = property(_ ## Get)
481 }
482 }
483 %enddef
484
485 %define %attributemap(Class, Type, Name, Get)
486 %rename(_ ## Get) sigrok::Class::Get;
487 %extend sigrok::Class
488 {
489 %pythoncode
490 {
491   Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
492 }
493 }
494 %enddef
495
496 %define %enumextras(Class)
497 %extend sigrok::Class
498 {
499   long __hash__()
500   {
501     return (long) $self;
502   }
503
504 %pythoncode
505 {
506   def __eq__(self, other):
507     return (type(self) is type(other) and hash(self) == hash(other))
508
509   def __ne__(self, other):
510     return (type(self) is not type(other) or hash(self) != hash(other))
511 }
512 }
513 %enddef
514
515 %include "../../../swig/classes.i"
516
517 /* Support Driver.scan() with keyword arguments. */
518 %extend sigrok::Driver
519 {
520     std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
521     {
522         if (!PyDict_Check(dict))
523             throw sigrok::Error(SR_ERR_ARG);
524
525         PyObject *py_key, *py_value;
526         Py_ssize_t pos = 0;
527         std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
528
529         while (PyDict_Next(dict, &pos, &py_key, &py_value))
530         {
531             if (!PyString_Check(py_key))
532                 throw sigrok::Error(SR_ERR_ARG);
533             auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
534             auto value = python_to_variant_by_key(py_value, key);
535             options[key] = value;
536         }
537
538         return $self->scan(options);
539     }
540 }
541
542 %pythoncode
543 {
544     def _Driver_scan(self, **kwargs):
545         return self._scan_kwargs(kwargs)
546
547     Driver.scan = _Driver_scan
548 }
549
550 /* Support InputFormat.create_input() with keyword arguments. */
551 %extend sigrok::InputFormat
552 {
553     std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
554     {
555         return $self->create_input(
556             dict_to_map_options(dict, $self->options()));
557     }
558 }
559
560 %pythoncode
561 {
562     def _InputFormat_create_input(self, **kwargs):
563         return self._create_input(kwargs)
564
565     InputFormat.create_input = _InputFormat_create_input
566 }
567
568 /* Support OutputFormat.create_output() with keyword arguments. */
569 %extend sigrok::OutputFormat
570 {
571     std::shared_ptr<sigrok::Output> _create_output_kwargs(
572         std::shared_ptr<sigrok::Device> device, PyObject *dict)
573     {
574         return $self->create_output(device,
575             dict_to_map_options(dict, $self->options()));
576     }
577 }
578
579 %pythoncode
580 {
581     def _OutputFormat_create_output(self, device, **kwargs):
582         return self._create_output_kwargs(device, kwargs)
583
584     OutputFormat.create_output = _OutputFormat_create_output
585 }
586
587 /* Support config_set() with Python input types. */
588 %extend sigrok::Configurable
589 {
590     void config_set(const ConfigKey *key, PyObject *input)
591     {
592         $self->config_set(key, python_to_variant_by_key(input, key));
593     }
594 }
595
596 /* Return NumPy array from Analog::data(). */
597 %extend sigrok::Analog
598 {
599     PyObject * _data()
600     {
601         int nd = 2;
602         npy_intp dims[2];
603         dims[0] = $self->channels().size();
604         dims[1] = $self->num_samples();
605         int typenum = NPY_FLOAT;
606         void *data = $self->data_pointer();
607         return PyArray_SimpleNewFromData(nd, dims, typenum, data);
608     }
609
610 %pythoncode
611 {
612     data = property(_data)
613 }
614 }