]> sigrok.org Git - libsigrok.git/blame_incremental - bindings/python/sigrok/core/classes.i
SR_DF_ANALOG_OLD and sr_datafeed_analog_old renames.
[libsigrok.git] / bindings / python / sigrok / core / classes.i
... / ...
CommitLineData
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
23Introduction
24------------
25
26The pysigrok API provides an object-oriented Python interface to the
27functionality in libsigrok. It is built on top of the libsigrokcxx 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
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
53PyObject *PyGObject_lib;
54PyObject *GLib;
55
56#include "config.h"
57
58#if PYGOBJECT_FLAGS_SIGNED
59typedef gint pyg_flags_type;
60#else
61typedef 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::AnalogOld> _payload_analog_old()
254 {
255 return dynamic_pointer_cast<sigrok::AnalogOld>($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_OLD:
275 return self._payload_analog_old()
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> */
288std::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. */
312Glib::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. */
333Glib::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> */
355std::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::AnalogOld::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 AnalogOld::data(). */
510%extend sigrok::AnalogOld
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}