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