]> sigrok.org Git - libsigrok.git/blame - 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
f7740954
ML
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
6a8c1d68
ML
20%define DOCSTRING
21"@mainpage API Reference
22
23Introduction
24------------
25
26The pysigrok API provides an object-oriented Python interface to the
52ff4f6a 27functionality in libsigrok. It is built on top of the libsigrokcxx C++ API.
6a8c1d68
ML
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
f7740954
ML
46
47%{
aae2273b 48#include <stdio.h>
f7740954 49#include <pygobject.h>
e6672888 50#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
ed6b4c47 51#include <numpy/arrayobject.h>
f7740954 52
aae2273b 53PyObject *PyGObject_lib;
f7740954 54PyObject *GLib;
f7740954 55
0e1a7fe9 56#include "config.h"
abc7146d
ML
57
58#if PYGOBJECT_FLAGS_SIGNED
59typedef gint pyg_flags_type;
60#else
61typedef guint pyg_flags_type;
62#endif
63
f7740954
ML
64%}
65
66%init %{
aae2273b
AG
67 PyGObject_lib = pygobject_init(-1, -1, -1);
68 if (!PyGObject_lib)
69 fprintf(stderr, "pygobject initialization failed.\n");
f7740954 70 GLib = PyImport_ImportModule("gi.repository.GLib");
aae2273b
AG
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");
a2e4d882 77#if PY_VERSION_HEX >= 0x03000000
fa72105f 78 return nullptr;
a2e4d882 79#else
aae2273b 80 return;
a2e4d882 81#endif
aae2273b 82 }
ed6b4c47 83 import_array();
f7740954
ML
84%}
85
86/* Map file objects to file descriptors. */
87%typecheck(SWIG_TYPECHECK_POINTER) int fd {
88 $1 = (PyObject_AsFileDescriptor($input) != -1);
89}
90
f7740954
ML
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,
fa72105f 98 const_cast<char *>("unpack"), nullptr);
f7740954
ML
99 Py_XDECREF(variant);
100 g_free(value);
101}
102
f7740954
ML
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
682fb08c 112 $1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
f7740954
ML
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);
75fb3036
ML
127
128 bool completed = !PyErr_Occurred();
129
130 if (!completed)
131 PyErr_Print();
132
133 bool valid_result = (completed && result == Py_None);
134
f7740954
ML
135 Py_XDECREF(result);
136
75fb3036
ML
137 if (completed && !valid_result)
138 {
139 PyErr_SetString(PyExc_TypeError,
140 "Log callback did not return None");
141 PyErr_Print();
142 }
143
f7740954 144 PyGILState_Release(gstate);
75fb3036
ML
145
146 if (!valid_result)
147 throw sigrok::Error(SR_ERR);
f7740954
ML
148 };
149
150 Py_XINCREF($input);
151}
152
2c3c9b99
DE
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
f7740954
ML
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);
75fb3036
ML
214
215 bool completed = !PyErr_Occurred();
216
217 if (!completed)
218 PyErr_Print();
219
220 bool valid_result = (completed && result == Py_None);
221
f7740954
ML
222 Py_XDECREF(result);
223
75fb3036
ML
224 if (completed && !valid_result)
225 {
226 PyErr_SetString(PyExc_TypeError,
227 "Datafeed callback did not return None");
228 PyErr_Print();
229 }
230
f7740954 231 PyGILState_Release(gstate);
75fb3036
ML
232
233 if (!valid_result)
234 throw sigrok::Error(SR_ERR);
f7740954
ML
235 };
236
237 Py_XINCREF($input);
238}
239
ea22dc10
ML
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 }
5faebab2 253 std::shared_ptr<sigrok::AnalogOld> _payload_analog_old()
ea22dc10 254 {
5faebab2 255 return dynamic_pointer_cast<sigrok::AnalogOld>($self->payload());
ea22dc10
ML
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()
5faebab2
UH
274 elif self.type == PacketType.ANALOG_OLD:
275 return self._payload_analog_old()
ea22dc10
ML
276 else:
277 return None
278
279 payload = property(_payload)
280}
281}
282
f7740954
ML
283%{
284
161dc24d 285#include "libsigrokcxx/libsigrokcxx.hpp"
f7740954
ML
286
287/* Convert from a Python dict to a std::map<std::string, std::string> */
58aa1f83 288std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
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{
9d229ecb 314 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
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))
f90ed2d1 321 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
f7740954
ML
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
58aa1f83
ML
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{
3b161085 336 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
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))
f90ed2d1 343 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
58aa1f83
ML
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
f7740954
ML
377%}
378
379/* Ignore these methods, we will override them below. */
5faebab2 380%ignore sigrok::AnalogOld::data;
f7740954 381%ignore sigrok::Driver::scan;
ca3291e3 382%ignore sigrok::InputFormat::create_input;
f7740954
ML
383%ignore sigrok::OutputFormat::create_output;
384
bd4fda24
ML
385%include "doc.i"
386
062430a2 387%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
388%rename(_ ## Get) sigrok::Class::Get;
389%extend sigrok::Class
390{
391%pythoncode
392{
393 Name = property(_ ## Get)
394}
395}
062430a2
ML
396%enddef
397
398%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
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}
062430a2
ML
407%enddef
408
7a36ceac 409%define %enumextras(Class)
f0c0dab5
ML
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}
7a36ceac
ML
426%enddef
427
f7740954
ML
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);
0bc1a761 446 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
f7740954
ML
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
ca3291e3 463/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
464%extend sigrok::InputFormat
465{
ca3291e3 466 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 467 {
ca3291e3 468 return $self->create_input(
3b161085 469 dict_to_map_options(dict, $self->options()));
f7740954
ML
470 }
471}
472
473%pythoncode
474{
ca3291e3
ML
475 def _InputFormat_create_input(self, **kwargs):
476 return self._create_input(kwargs)
f7740954 477
ca3291e3 478 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
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 {
58aa1f83 487 return $self->create_output(device,
3b161085 488 dict_to_map_options(dict, $self->options()));
f7740954
ML
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}
ed6b4c47 508
5faebab2
UH
509/* Return NumPy array from AnalogOld::data(). */
510%extend sigrok::AnalogOld
ed6b4c47
ML
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}