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