]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
output/csv: use intermediate time_t var, silence compiler warning
[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
8491cf7c
ML
115/* Use the same typemap above for Glib::VariantContainerBase */
116%apply Glib::VariantBase { Glib::VariantContainerBase }
117
f7740954
ML
118/* Map from callable PyObject to LogCallbackFunction */
119%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
120 $1 = PyCallable_Check($input);
121}
122
123%typemap(in) sigrok::LogCallbackFunction {
124 if (!PyCallable_Check($input))
125 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
126
682fb08c 127 $1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
f7740954
ML
128 auto gstate = PyGILState_Ensure();
129
130 auto log_obj = SWIG_NewPointerObj(
131 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
132
ae2cdde4 133 auto string_obj = string_to_python(message.c_str());
f7740954
ML
134
135 auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
136
5bc81745 137 auto result = PyObject_CallObject($input, arglist);
f7740954
ML
138
139 Py_XDECREF(arglist);
140 Py_XDECREF(log_obj);
141 Py_XDECREF(string_obj);
75fb3036
ML
142
143 bool completed = !PyErr_Occurred();
144
145 if (!completed)
146 PyErr_Print();
147
148 bool valid_result = (completed && result == Py_None);
149
f7740954
ML
150 Py_XDECREF(result);
151
75fb3036
ML
152 if (completed && !valid_result)
153 {
154 PyErr_SetString(PyExc_TypeError,
155 "Log callback did not return None");
156 PyErr_Print();
157 }
158
f7740954 159 PyGILState_Release(gstate);
75fb3036
ML
160
161 if (!valid_result)
162 throw sigrok::Error(SR_ERR);
f7740954
ML
163 };
164
165 Py_XINCREF($input);
166}
167
2c3c9b99
DE
168/* Map from callable PyObject to SessionStoppedCallback */
169%typecheck(SWIG_TYPECHECK_POINTER) sigrok::SessionStoppedCallback {
170 $1 = PyCallable_Check($input);
171}
172
173%typemap(in) sigrok::SessionStoppedCallback {
174 if (!PyCallable_Check($input))
175 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
176
177 $1 = [=] () {
178 const auto gstate = PyGILState_Ensure();
179
5bc81745 180 const auto result = PyObject_CallObject($input, nullptr);
2c3c9b99
DE
181 const bool completed = !PyErr_Occurred();
182 const bool valid_result = (completed && result == Py_None);
183
184 if (completed && !valid_result) {
185 PyErr_SetString(PyExc_TypeError,
186 "Session stop callback did not return None");
187 }
188 if (!valid_result)
189 PyErr_Print();
190
191 Py_XDECREF(result);
192 PyGILState_Release(gstate);
193
194 if (!valid_result)
195 throw sigrok::Error(SR_ERR);
196 };
197
198 Py_XINCREF($input);
199}
200
f7740954
ML
201/* Map from callable PyObject to DatafeedCallbackFunction */
202%typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
203 $1 = PyCallable_Check($input);
204}
205
206%typemap(in) sigrok::DatafeedCallbackFunction {
207 if (!PyCallable_Check($input))
208 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
209
210 $1 = [=] (std::shared_ptr<sigrok::Device> device,
211 std::shared_ptr<sigrok::Packet> packet) {
212 auto gstate = PyGILState_Ensure();
213
214 auto device_obj = SWIG_NewPointerObj(
215 SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
216 SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
217
218 auto packet_obj = SWIG_NewPointerObj(
219 SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
220 SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
221
222 auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
223
5bc81745 224 auto result = PyObject_CallObject($input, arglist);
f7740954
ML
225
226 Py_XDECREF(arglist);
227 Py_XDECREF(device_obj);
228 Py_XDECREF(packet_obj);
75fb3036
ML
229
230 bool completed = !PyErr_Occurred();
231
232 if (!completed)
233 PyErr_Print();
234
235 bool valid_result = (completed && result == Py_None);
236
f7740954
ML
237 Py_XDECREF(result);
238
75fb3036
ML
239 if (completed && !valid_result)
240 {
241 PyErr_SetString(PyExc_TypeError,
242 "Datafeed callback did not return None");
243 PyErr_Print();
244 }
245
f7740954 246 PyGILState_Release(gstate);
75fb3036
ML
247
248 if (!valid_result)
249 throw sigrok::Error(SR_ERR);
f7740954
ML
250 };
251
252 Py_XINCREF($input);
253}
254
ea22dc10
ML
255/* Cast PacketPayload pointers to correct subclass type. */
256%ignore sigrok::Packet::payload;
257
258%extend sigrok::Packet
259{
260 std::shared_ptr<sigrok::Header> _payload_header()
261 {
262 return dynamic_pointer_cast<sigrok::Header>($self->payload());
263 }
264 std::shared_ptr<sigrok::Meta> _payload_meta()
265 {
266 return dynamic_pointer_cast<sigrok::Meta>($self->payload());
267 }
dd13d47a 268 std::shared_ptr<sigrok::Analog> _payload_analog()
ea22dc10 269 {
dd13d47a 270 return dynamic_pointer_cast<sigrok::Analog>($self->payload());
ea22dc10
ML
271 }
272 std::shared_ptr<sigrok::Logic> _payload_logic()
273 {
274 return dynamic_pointer_cast<sigrok::Logic>($self->payload());
275 }
276}
277
278%extend sigrok::Packet
279{
280%pythoncode
281{
282 def _payload(self):
283 if self.type == PacketType.HEADER:
284 return self._payload_header()
285 elif self.type == PacketType.META:
286 return self._payload_meta()
287 elif self.type == PacketType.LOGIC:
288 return self._payload_logic()
dd13d47a
UH
289 elif self.type == PacketType.ANALOG:
290 return self._payload_analog()
ea22dc10
ML
291 else:
292 return None
293
294 payload = property(_payload)
295}
296}
297
f7740954
ML
298%{
299
161dc24d 300#include "libsigrokcxx/libsigrokcxx.hpp"
f7740954
ML
301
302/* Convert from a Python dict to a std::map<std::string, std::string> */
58aa1f83 303std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
304{
305 if (!PyDict_Check(dict))
306 throw sigrok::Error(SR_ERR_ARG);
307
308 std::map<std::string, std::string> output;
309
310 PyObject *py_key, *py_value;
311 Py_ssize_t pos = 0;
312
313 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
ae2cdde4 314 if (!string_check(py_key))
f7740954 315 throw sigrok::Error(SR_ERR_ARG);
ae2cdde4 316 if (!string_check(py_value))
f7740954 317 throw sigrok::Error(SR_ERR_ARG);
ae2cdde4
ML
318 auto key = string_from_python(py_key);
319 auto value = string_from_python(py_value);
f7740954
ML
320 output[key] = value;
321 }
322
323 return output;
324}
325
326/* Convert from a Python type to Glib::Variant, according to config key data type. */
327Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
328{
9d229ecb 329 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
330
331 if (type == SR_T_UINT64 && PyInt_Check(input))
332 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
333 if (type == SR_T_UINT64 && PyLong_Check(input))
334 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
ae2cdde4
ML
335 else if (type == SR_T_STRING && string_check(input))
336 return Glib::Variant<Glib::ustring>::create(string_from_python(input));
f7740954
ML
337 else if (type == SR_T_BOOL && PyBool_Check(input))
338 return Glib::Variant<bool>::create(input == Py_True);
339 else if (type == SR_T_FLOAT && PyFloat_Check(input))
340 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
341 else if (type == SR_T_INT32 && PyInt_Check(input))
342 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
0db1b189
MH
343 else if (type == SR_T_UINT32 && PyInt_Check(input))
344 return Glib::Variant<guint32>::create(PyInt_AsLong(input));
a2916ad0
RA
345 else if ((type == SR_T_RATIONAL_VOLT) && PyTuple_Check(input) && (PyTuple_Size(input) == 2)) {
346 PyObject *numObj = PyTuple_GetItem(input, 0);
347 PyObject *denomObj = PyTuple_GetItem(input, 1);
348 if ((PyInt_Check(numObj) || PyLong_Check(numObj)) && (PyInt_Check(denomObj) || PyLong_Check(denomObj))) {
004fd9ff
SA
349 const std::vector<guint64> v = {(guint64)PyInt_AsLong(numObj), (guint64)PyInt_AsLong(denomObj)};
350 return Glib::Variant< std::vector<guint64> >::create(v);
a2916ad0
RA
351 }
352 }
353 throw sigrok::Error(SR_ERR_ARG);
f7740954
ML
354}
355
58aa1f83
ML
356/* Convert from a Python type to Glib::Variant, according to Option data type. */
357Glib::VariantBase python_to_variant_by_option(PyObject *input,
358 std::shared_ptr<sigrok::Option> option)
359{
3b161085 360 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
361
362 if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
363 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
364 if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
365 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
ae2cdde4
ML
366 else if (type == G_VARIANT_TYPE_STRING && string_check(input))
367 return Glib::Variant<Glib::ustring>::create(string_from_python(input));
58aa1f83
ML
368 else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
369 return Glib::Variant<bool>::create(input == Py_True);
370 else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
371 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
372 else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
373 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
0db1b189
MH
374 else if (type == G_VARIANT_TYPE_UINT32 && PyInt_Check(input))
375 return Glib::Variant<guint32>::create(PyInt_AsLong(input));
58aa1f83
ML
376 else
377 throw sigrok::Error(SR_ERR_ARG);
378}
379
380/* Convert from a Python dict to a std::map<std::string, std::string> */
381std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
382 std::map<std::string, std::shared_ptr<sigrok::Option> > options)
383{
384 if (!PyDict_Check(dict))
385 throw sigrok::Error(SR_ERR_ARG);
386
387 std::map<std::string, Glib::VariantBase> output;
388
389 PyObject *py_key, *py_value;
390 Py_ssize_t pos = 0;
391
392 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
ae2cdde4 393 if (!string_check(py_key))
58aa1f83 394 throw sigrok::Error(SR_ERR_ARG);
ae2cdde4 395 auto key = string_from_python(py_key);
58aa1f83
ML
396 auto value = python_to_variant_by_option(py_value, options[key]);
397 output[key] = value;
398 }
399
400 return output;
401}
402
f7740954
ML
403%}
404
405/* Ignore these methods, we will override them below. */
dd13d47a 406%ignore sigrok::Analog::data;
49052159 407%ignore sigrok::Logic::data;
f7740954 408%ignore sigrok::Driver::scan;
ca3291e3 409%ignore sigrok::InputFormat::create_input;
f7740954
ML
410%ignore sigrok::OutputFormat::create_output;
411
df979d6d 412%include "doc_start.i"
bd4fda24 413
062430a2 414%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
415%rename(_ ## Get) sigrok::Class::Get;
416%extend sigrok::Class
417{
418%pythoncode
419{
420 Name = property(_ ## Get)
421}
422}
062430a2
ML
423%enddef
424
425%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
426%rename(_ ## Get) sigrok::Class::Get;
427%extend sigrok::Class
428{
429%pythoncode
430{
431 Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
432}
433}
062430a2
ML
434%enddef
435
7a36ceac 436%define %enumextras(Class)
f0c0dab5
ML
437%extend sigrok::Class
438{
439 long __hash__()
440 {
441 return (long) $self;
442 }
443
c61e208d
ML
444 std::string __str__()
445 {
446 return $self->name();
447 }
448
449 std::string __repr__()
450 {
451 return "Class." + $self->name();
452 }
453
f0c0dab5
ML
454%pythoncode
455{
456 def __eq__(self, other):
457 return (type(self) is type(other) and hash(self) == hash(other))
458
459 def __ne__(self, other):
460 return (type(self) is not type(other) or hash(self) != hash(other))
461}
462}
7a36ceac
ML
463%enddef
464
f7740954
ML
465%include "../../../swig/classes.i"
466
467/* Support Driver.scan() with keyword arguments. */
468%extend sigrok::Driver
469{
470 std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
471 {
472 if (!PyDict_Check(dict))
473 throw sigrok::Error(SR_ERR_ARG);
474
475 PyObject *py_key, *py_value;
476 Py_ssize_t pos = 0;
477 std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
478
479 while (PyDict_Next(dict, &pos, &py_key, &py_value))
480 {
ae2cdde4 481 if (!string_check(py_key))
f7740954 482 throw sigrok::Error(SR_ERR_ARG);
ae2cdde4 483 auto key = sigrok::ConfigKey::get_by_identifier(string_from_python(py_key));
f7740954
ML
484 auto value = python_to_variant_by_key(py_value, key);
485 options[key] = value;
486 }
487
488 return $self->scan(options);
489 }
490}
491
492%pythoncode
493{
494 def _Driver_scan(self, **kwargs):
495 return self._scan_kwargs(kwargs)
496
497 Driver.scan = _Driver_scan
498}
499
ca3291e3 500/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
501%extend sigrok::InputFormat
502{
ca3291e3 503 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 504 {
ca3291e3 505 return $self->create_input(
3b161085 506 dict_to_map_options(dict, $self->options()));
f7740954
ML
507 }
508}
509
510%pythoncode
511{
ca3291e3
ML
512 def _InputFormat_create_input(self, **kwargs):
513 return self._create_input(kwargs)
f7740954 514
ca3291e3 515 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
516}
517
518/* Support OutputFormat.create_output() with keyword arguments. */
519%extend sigrok::OutputFormat
520{
521 std::shared_ptr<sigrok::Output> _create_output_kwargs(
522 std::shared_ptr<sigrok::Device> device, PyObject *dict)
523 {
58aa1f83 524 return $self->create_output(device,
3b161085 525 dict_to_map_options(dict, $self->options()));
f7740954
ML
526 }
527}
528
529%pythoncode
530{
531 def _OutputFormat_create_output(self, device, **kwargs):
532 return self._create_output_kwargs(device, kwargs)
533
534 OutputFormat.create_output = _OutputFormat_create_output
535}
536
537/* Support config_set() with Python input types. */
538%extend sigrok::Configurable
539{
540 void config_set(const ConfigKey *key, PyObject *input)
541 {
542 $self->config_set(key, python_to_variant_by_key(input, key));
543 }
544}
ed6b4c47 545
dd13d47a
UH
546/* Return NumPy array from Analog::data(). */
547%extend sigrok::Analog
ed6b4c47
ML
548{
549 PyObject * _data()
550 {
551 int nd = 2;
552 npy_intp dims[2];
553 dims[0] = $self->channels().size();
554 dims[1] = $self->num_samples();
555 int typenum = NPY_FLOAT;
556 void *data = $self->data_pointer();
557 return PyArray_SimpleNewFromData(nd, dims, typenum, data);
558 }
559
560%pythoncode
561{
562 data = property(_data)
563}
564}
df979d6d 565
49052159
SBO
566/* Return NumPy array from Logic::data(). */
567%extend sigrok::Logic
568{
569 PyObject * _data()
570 {
571 npy_intp dims[2];
572 dims[0] = $self->data_length() / $self->unit_size();
573 dims[1] = $self->unit_size();
574 int typenum = NPY_UINT8;
575 void *data = $self->data_pointer();
576 return PyArray_SimpleNewFromData(2, dims, typenum, data);
577 }
578
579%pythoncode
580{
581 data = property(_data)
582}
583}
584
62bd644f
ML
585/* Create logic packet from Python buffer. */
586%extend sigrok::Context
587{
588 std::shared_ptr<Packet> _create_logic_packet_buf(PyObject *buf, unsigned int unit_size)
589 {
590 Py_buffer view;
591 PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE);
592 return $self->create_logic_packet(view.buf, view.len, unit_size);
593 }
594}
595
596%pythoncode
597{
598 def _Context_create_logic_packet(self, buf, unit_size):
599 return self._create_logic_packet_buf(buf, unit_size)
600
601 Context.create_logic_packet = _Context_create_logic_packet
602}
49052159 603
df979d6d 604%include "doc_end.i"