]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
python: Add override for Context.create_logic_packet()
[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%{
21964348
GS
48#include "config.h"
49
aae2273b 50#include <stdio.h>
f7740954 51#include <pygobject.h>
e6672888 52#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
ed6b4c47 53#include <numpy/arrayobject.h>
f7740954 54
aae2273b 55PyObject *PyGObject_lib;
f7740954 56PyObject *GLib;
f7740954 57
abc7146d
ML
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;
49052159 393%ignore sigrok::Logic::data;
f7740954 394%ignore sigrok::Driver::scan;
ca3291e3 395%ignore sigrok::InputFormat::create_input;
f7740954
ML
396%ignore sigrok::OutputFormat::create_output;
397
df979d6d 398%include "doc_start.i"
bd4fda24 399
062430a2 400%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
401%rename(_ ## Get) sigrok::Class::Get;
402%extend sigrok::Class
403{
404%pythoncode
405{
406 Name = property(_ ## Get)
407}
408}
062430a2
ML
409%enddef
410
411%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
412%rename(_ ## Get) sigrok::Class::Get;
413%extend sigrok::Class
414{
415%pythoncode
416{
417 Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
418}
419}
062430a2
ML
420%enddef
421
7a36ceac 422%define %enumextras(Class)
f0c0dab5
ML
423%extend sigrok::Class
424{
425 long __hash__()
426 {
427 return (long) $self;
428 }
429
c61e208d
ML
430 std::string __str__()
431 {
432 return $self->name();
433 }
434
435 std::string __repr__()
436 {
437 return "Class." + $self->name();
438 }
439
f0c0dab5
ML
440%pythoncode
441{
442 def __eq__(self, other):
443 return (type(self) is type(other) and hash(self) == hash(other))
444
445 def __ne__(self, other):
446 return (type(self) is not type(other) or hash(self) != hash(other))
447}
448}
7a36ceac
ML
449%enddef
450
f7740954
ML
451%include "../../../swig/classes.i"
452
453/* Support Driver.scan() with keyword arguments. */
454%extend sigrok::Driver
455{
456 std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
457 {
458 if (!PyDict_Check(dict))
459 throw sigrok::Error(SR_ERR_ARG);
460
461 PyObject *py_key, *py_value;
462 Py_ssize_t pos = 0;
463 std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
464
465 while (PyDict_Next(dict, &pos, &py_key, &py_value))
466 {
ae2cdde4 467 if (!string_check(py_key))
f7740954 468 throw sigrok::Error(SR_ERR_ARG);
ae2cdde4 469 auto key = sigrok::ConfigKey::get_by_identifier(string_from_python(py_key));
f7740954
ML
470 auto value = python_to_variant_by_key(py_value, key);
471 options[key] = value;
472 }
473
474 return $self->scan(options);
475 }
476}
477
478%pythoncode
479{
480 def _Driver_scan(self, **kwargs):
481 return self._scan_kwargs(kwargs)
482
483 Driver.scan = _Driver_scan
484}
485
ca3291e3 486/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
487%extend sigrok::InputFormat
488{
ca3291e3 489 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 490 {
ca3291e3 491 return $self->create_input(
3b161085 492 dict_to_map_options(dict, $self->options()));
f7740954
ML
493 }
494}
495
496%pythoncode
497{
ca3291e3
ML
498 def _InputFormat_create_input(self, **kwargs):
499 return self._create_input(kwargs)
f7740954 500
ca3291e3 501 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
502}
503
504/* Support OutputFormat.create_output() with keyword arguments. */
505%extend sigrok::OutputFormat
506{
507 std::shared_ptr<sigrok::Output> _create_output_kwargs(
508 std::shared_ptr<sigrok::Device> device, PyObject *dict)
509 {
58aa1f83 510 return $self->create_output(device,
3b161085 511 dict_to_map_options(dict, $self->options()));
f7740954
ML
512 }
513}
514
515%pythoncode
516{
517 def _OutputFormat_create_output(self, device, **kwargs):
518 return self._create_output_kwargs(device, kwargs)
519
520 OutputFormat.create_output = _OutputFormat_create_output
521}
522
523/* Support config_set() with Python input types. */
524%extend sigrok::Configurable
525{
526 void config_set(const ConfigKey *key, PyObject *input)
527 {
528 $self->config_set(key, python_to_variant_by_key(input, key));
529 }
530}
ed6b4c47 531
dd13d47a
UH
532/* Return NumPy array from Analog::data(). */
533%extend sigrok::Analog
ed6b4c47
ML
534{
535 PyObject * _data()
536 {
537 int nd = 2;
538 npy_intp dims[2];
539 dims[0] = $self->channels().size();
540 dims[1] = $self->num_samples();
541 int typenum = NPY_FLOAT;
542 void *data = $self->data_pointer();
543 return PyArray_SimpleNewFromData(nd, dims, typenum, data);
544 }
545
546%pythoncode
547{
548 data = property(_data)
549}
550}
df979d6d 551
49052159
SBO
552/* Return NumPy array from Logic::data(). */
553%extend sigrok::Logic
554{
555 PyObject * _data()
556 {
557 npy_intp dims[2];
558 dims[0] = $self->data_length() / $self->unit_size();
559 dims[1] = $self->unit_size();
560 int typenum = NPY_UINT8;
561 void *data = $self->data_pointer();
562 return PyArray_SimpleNewFromData(2, dims, typenum, data);
563 }
564
565%pythoncode
566{
567 data = property(_data)
568}
569}
570
62bd644f
ML
571/* Create logic packet from Python buffer. */
572%extend sigrok::Context
573{
574 std::shared_ptr<Packet> _create_logic_packet_buf(PyObject *buf, unsigned int unit_size)
575 {
576 Py_buffer view;
577 PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE);
578 return $self->create_logic_packet(view.buf, view.len, unit_size);
579 }
580}
581
582%pythoncode
583{
584 def _Context_create_logic_packet(self, buf, unit_size):
585 return self._create_logic_packet_buf(buf, unit_size)
586
587 Context.create_logic_packet = _Context_create_logic_packet
588}
49052159 589
df979d6d 590%include "doc_end.i"