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