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