]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
python: Return correct PacketPayload subclasses from Packet.payload()
[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
27functionality in libsigrok. It is built on top of the sigrok++ C++ API.
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%{
48#include <pygobject.h>
49
50PyObject *GLib;
51PyTypeObject *IOChannel;
52PyTypeObject *PollFD;
53
0e1a7fe9 54#include "config.h"
abc7146d
ML
55
56#if PYGOBJECT_FLAGS_SIGNED
57typedef gint pyg_flags_type;
58#else
59typedef guint pyg_flags_type;
60#endif
61
f7740954
ML
62%}
63
64%init %{
65 pygobject_init(-1, -1, -1);
66 GLib = PyImport_ImportModule("gi.repository.GLib");
67 IOChannel = (PyTypeObject *) PyObject_GetAttrString(GLib, "IOChannel");
68 PollFD = (PyTypeObject *) PyObject_GetAttrString(GLib, "PollFD");
69%}
70
71/* Map file objects to file descriptors. */
72%typecheck(SWIG_TYPECHECK_POINTER) int fd {
73 $1 = (PyObject_AsFileDescriptor($input) != -1);
74}
75
76%typemap(in) int fd {
77 int fd = PyObject_AsFileDescriptor($input);
78 if (fd == -1)
79 SWIG_exception(SWIG_TypeError,
80 "Expected file object or integer file descriptor");
81 else
82 $1 = fd;
83}
84
85/* Map from Glib::Variant to native Python types. */
86%typemap(out) Glib::VariantBase {
87 GValue *value = g_new0(GValue, 1);
88 g_value_init(value, G_TYPE_VARIANT);
89 g_value_set_variant(value, $1.gobj());
90 PyObject *variant = pyg_value_as_pyobject(value, true);
91 $result = PyObject_CallMethod(variant,
92 const_cast<char *>("unpack"),
93 const_cast<char *>(""), NULL);
94 Py_XDECREF(variant);
95 g_free(value);
96}
97
98/* Map from Glib::IOCondition to GLib.IOCondition. */
99%typecheck(SWIG_TYPECHECK_POINTER) Glib::IOCondition {
abc7146d 100 pyg_flags_type flags;
f7740954
ML
101 $1 = pygobject_check($input, &PyGFlags_Type) &&
102 (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) != -1);
103}
104
105%typemap(in) Glib::IOCondition {
106 if (!pygobject_check($input, &PyGFlags_Type))
107 SWIG_exception(SWIG_TypeError, "Expected GLib.IOCondition value");
abc7146d 108 pyg_flags_type flags;
f7740954
ML
109 if (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) == -1)
110 SWIG_exception(SWIG_TypeError, "Not a valid Glib.IOCondition value");
111 $1 = (Glib::IOCondition) flags;
112}
113
114/* And back */
115%typemap(out) Glib::IOCondition {
116 GValue *value = g_new0(GValue, 1);
117 g_value_init(value, G_TYPE_IO_CONDITION);
118 g_value_set_flags(value, &$1);
119 $result = pyg_value_as_pyobject(value, true);
120 g_free(value);
121}
122
123/* Map from GLib.PollFD to Glib::PollFD *. */
124%typecheck(SWIG_TYPECHECK_POINTER) Glib::PollFD {
125 $1 = pygobject_check($input, PollFD);
126}
127
128%typemap(in) Glib::PollFD {
129 if (!pygobject_check($input, PollFD))
130 SWIG_exception(SWIG_TypeError, "Expected GLib.PollFD");
131 PyObject *fd_obj = PyObject_GetAttrString($input, "fd");
132 PyObject *events_obj = PyObject_GetAttrString($input, "events");
abc7146d 133 pyg_flags_type flags;
f7740954
ML
134 pyg_flags_get_value(G_TYPE_IO_CONDITION, events_obj, &flags);
135 int fd = PyInt_AsLong(fd_obj);
136 Glib::IOCondition events = (Glib::IOCondition) flags;
137 $1 = Glib::PollFD(fd, events);
138}
139
140/* Map from GLib.IOChannel to Glib::IOChannel *. */
141%typecheck(SWIG_TYPECHECK_POINTER) Glib::RefPtr<Glib::IOChannel> {
142 $1 = pygobject_check($input, IOChannel);
143}
144
145%typemap(in) Glib::RefPtr<Glib::IOChannel> {
146 if (!pygobject_check($input, IOChannel))
147 SWIG_exception(SWIG_TypeError, "Expected GLib.IOChannel");
148 $1 = Glib::wrap((GIOChannel *) PyObject_Hash($input), true);
149}
150
151/* Map from callable PyObject to SourceCallbackFunction. */
152%typecheck(SWIG_TYPECHECK_POINTER) sigrok::SourceCallbackFunction {
153 $1 = PyCallable_Check($input);
154}
155
156%typemap(in) sigrok::SourceCallbackFunction {
157 if (!PyCallable_Check($input))
158 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
159
160 $1 = [=] (Glib::IOCondition revents) {
161 auto gstate = PyGILState_Ensure();
162
163 GValue *value = g_new0(GValue, 1);
164 g_value_init(value, G_TYPE_IO_CONDITION);
165 g_value_set_flags(value, revents);
166 auto revents_obj = pyg_value_as_pyobject(value, true);
167 g_free(value);
168
169 auto arglist = Py_BuildValue("(O)", revents_obj);
170
171 auto result = PyEval_CallObject($input, arglist);
172
173 Py_XDECREF(arglist);
174 Py_XDECREF(revents_obj);
175
75fb3036
ML
176 bool completed = !PyErr_Occurred();
177
178 if (!completed)
179 PyErr_Print();
180
181 bool valid_result = (completed && PyBool_Check(result));
f7740954 182
75fb3036
ML
183 if (completed && !valid_result)
184 {
185 PyErr_SetString(PyExc_TypeError,
186 "EventSource callback did not return a boolean");
187 PyErr_Print();
188 }
189
190 bool retval = (valid_result && result == Py_True);
f7740954
ML
191
192 Py_XDECREF(result);
193
194 PyGILState_Release(gstate);
195
75fb3036
ML
196 if (!valid_result)
197 throw sigrok::Error(SR_ERR);
198
f7740954
ML
199 return retval;
200 };
201
202 Py_XINCREF($input);
203}
204
205/* Map from callable PyObject to LogCallbackFunction */
206%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
207 $1 = PyCallable_Check($input);
208}
209
210%typemap(in) sigrok::LogCallbackFunction {
211 if (!PyCallable_Check($input))
212 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
213
214 $1 = [=] (const sigrok::LogLevel *loglevel, string message) {
215 auto gstate = PyGILState_Ensure();
216
217 auto log_obj = SWIG_NewPointerObj(
218 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
219
220 auto string_obj = PyString_FromString(message.c_str());
221
222 auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
223
224 auto result = PyEval_CallObject($input, arglist);
225
226 Py_XDECREF(arglist);
227 Py_XDECREF(log_obj);
228 Py_XDECREF(string_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 "Log 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
255/* Map from callable PyObject to DatafeedCallbackFunction */
256%typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
257 $1 = PyCallable_Check($input);
258}
259
260%typemap(in) sigrok::DatafeedCallbackFunction {
261 if (!PyCallable_Check($input))
262 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
263
264 $1 = [=] (std::shared_ptr<sigrok::Device> device,
265 std::shared_ptr<sigrok::Packet> packet) {
266 auto gstate = PyGILState_Ensure();
267
268 auto device_obj = SWIG_NewPointerObj(
269 SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
270 SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
271
272 auto packet_obj = SWIG_NewPointerObj(
273 SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
274 SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
275
276 auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
277
278 auto result = PyEval_CallObject($input, arglist);
279
280 Py_XDECREF(arglist);
281 Py_XDECREF(device_obj);
282 Py_XDECREF(packet_obj);
75fb3036
ML
283
284 bool completed = !PyErr_Occurred();
285
286 if (!completed)
287 PyErr_Print();
288
289 bool valid_result = (completed && result == Py_None);
290
f7740954
ML
291 Py_XDECREF(result);
292
75fb3036
ML
293 if (completed && !valid_result)
294 {
295 PyErr_SetString(PyExc_TypeError,
296 "Datafeed callback did not return None");
297 PyErr_Print();
298 }
299
f7740954 300 PyGILState_Release(gstate);
75fb3036
ML
301
302 if (!valid_result)
303 throw sigrok::Error(SR_ERR);
f7740954
ML
304 };
305
306 Py_XINCREF($input);
307}
308
ea22dc10
ML
309/* Cast PacketPayload pointers to correct subclass type. */
310%ignore sigrok::Packet::payload;
311
312%extend sigrok::Packet
313{
314 std::shared_ptr<sigrok::Header> _payload_header()
315 {
316 return dynamic_pointer_cast<sigrok::Header>($self->payload());
317 }
318 std::shared_ptr<sigrok::Meta> _payload_meta()
319 {
320 return dynamic_pointer_cast<sigrok::Meta>($self->payload());
321 }
322 std::shared_ptr<sigrok::Analog> _payload_analog()
323 {
324 return dynamic_pointer_cast<sigrok::Analog>($self->payload());
325 }
326 std::shared_ptr<sigrok::Logic> _payload_logic()
327 {
328 return dynamic_pointer_cast<sigrok::Logic>($self->payload());
329 }
330}
331
332%extend sigrok::Packet
333{
334%pythoncode
335{
336 def _payload(self):
337 if self.type == PacketType.HEADER:
338 return self._payload_header()
339 elif self.type == PacketType.META:
340 return self._payload_meta()
341 elif self.type == PacketType.LOGIC:
342 return self._payload_logic()
343 elif self.type == PacketType.ANALOG:
344 return self._payload_analog()
345 else:
346 return None
347
348 payload = property(_payload)
349}
350}
351
f7740954
ML
352%{
353
354#include "libsigrok/libsigrok.hpp"
355
356/* Convert from a Python dict to a std::map<std::string, std::string> */
58aa1f83 357std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
358{
359 if (!PyDict_Check(dict))
360 throw sigrok::Error(SR_ERR_ARG);
361
362 std::map<std::string, std::string> output;
363
364 PyObject *py_key, *py_value;
365 Py_ssize_t pos = 0;
366
367 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
368 if (!PyString_Check(py_key))
369 throw sigrok::Error(SR_ERR_ARG);
370 if (!PyString_Check(py_value))
371 throw sigrok::Error(SR_ERR_ARG);
372 auto key = PyString_AsString(py_key);
373 auto value = PyString_AsString(py_value);
374 output[key] = value;
375 }
376
377 return output;
378}
379
380/* Convert from a Python type to Glib::Variant, according to config key data type. */
381Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
382{
9d229ecb 383 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
384
385 if (type == SR_T_UINT64 && PyInt_Check(input))
386 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
387 if (type == SR_T_UINT64 && PyLong_Check(input))
388 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
389 else if (type == SR_T_STRING && PyString_Check(input))
f90ed2d1 390 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
f7740954
ML
391 else if (type == SR_T_BOOL && PyBool_Check(input))
392 return Glib::Variant<bool>::create(input == Py_True);
393 else if (type == SR_T_FLOAT && PyFloat_Check(input))
394 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
395 else if (type == SR_T_INT32 && PyInt_Check(input))
396 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
397 else
398 throw sigrok::Error(SR_ERR_ARG);
399}
400
58aa1f83
ML
401/* Convert from a Python type to Glib::Variant, according to Option data type. */
402Glib::VariantBase python_to_variant_by_option(PyObject *input,
403 std::shared_ptr<sigrok::Option> option)
404{
3b161085 405 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
406
407 if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
408 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
409 if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
410 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
411 else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
f90ed2d1 412 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
58aa1f83
ML
413 else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
414 return Glib::Variant<bool>::create(input == Py_True);
415 else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
416 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
417 else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
418 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
419 else
420 throw sigrok::Error(SR_ERR_ARG);
421}
422
423/* Convert from a Python dict to a std::map<std::string, std::string> */
424std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
425 std::map<std::string, std::shared_ptr<sigrok::Option> > options)
426{
427 if (!PyDict_Check(dict))
428 throw sigrok::Error(SR_ERR_ARG);
429
430 std::map<std::string, Glib::VariantBase> output;
431
432 PyObject *py_key, *py_value;
433 Py_ssize_t pos = 0;
434
435 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
436 if (!PyString_Check(py_key))
437 throw sigrok::Error(SR_ERR_ARG);
438 auto key = PyString_AsString(py_key);
439 auto value = python_to_variant_by_option(py_value, options[key]);
440 output[key] = value;
441 }
442
443 return output;
444}
445
f7740954
ML
446%}
447
448/* Ignore these methods, we will override them below. */
449%ignore sigrok::Driver::scan;
ca3291e3 450%ignore sigrok::InputFormat::create_input;
f7740954
ML
451%ignore sigrok::OutputFormat::create_output;
452
bd4fda24
ML
453%include "doc.i"
454
062430a2 455%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
456%rename(_ ## Get) sigrok::Class::Get;
457%extend sigrok::Class
458{
459%pythoncode
460{
461 Name = property(_ ## Get)
462}
463}
062430a2
ML
464%enddef
465
466%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
467%rename(_ ## Get) sigrok::Class::Get;
468%extend sigrok::Class
469{
470%pythoncode
471{
472 Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
473}
474}
062430a2
ML
475%enddef
476
7a36ceac 477%define %enumextras(Class)
f0c0dab5
ML
478%extend sigrok::Class
479{
480 long __hash__()
481 {
482 return (long) $self;
483 }
484
485%pythoncode
486{
487 def __eq__(self, other):
488 return (type(self) is type(other) and hash(self) == hash(other))
489
490 def __ne__(self, other):
491 return (type(self) is not type(other) or hash(self) != hash(other))
492}
493}
7a36ceac
ML
494%enddef
495
f7740954
ML
496%include "../../../swig/classes.i"
497
498/* Support Driver.scan() with keyword arguments. */
499%extend sigrok::Driver
500{
501 std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
502 {
503 if (!PyDict_Check(dict))
504 throw sigrok::Error(SR_ERR_ARG);
505
506 PyObject *py_key, *py_value;
507 Py_ssize_t pos = 0;
508 std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
509
510 while (PyDict_Next(dict, &pos, &py_key, &py_value))
511 {
512 if (!PyString_Check(py_key))
513 throw sigrok::Error(SR_ERR_ARG);
0bc1a761 514 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
f7740954
ML
515 auto value = python_to_variant_by_key(py_value, key);
516 options[key] = value;
517 }
518
519 return $self->scan(options);
520 }
521}
522
523%pythoncode
524{
525 def _Driver_scan(self, **kwargs):
526 return self._scan_kwargs(kwargs)
527
528 Driver.scan = _Driver_scan
529}
530
ca3291e3 531/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
532%extend sigrok::InputFormat
533{
ca3291e3 534 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 535 {
ca3291e3 536 return $self->create_input(
3b161085 537 dict_to_map_options(dict, $self->options()));
f7740954
ML
538 }
539}
540
541%pythoncode
542{
ca3291e3
ML
543 def _InputFormat_create_input(self, **kwargs):
544 return self._create_input(kwargs)
f7740954 545
ca3291e3 546 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
547}
548
549/* Support OutputFormat.create_output() with keyword arguments. */
550%extend sigrok::OutputFormat
551{
552 std::shared_ptr<sigrok::Output> _create_output_kwargs(
553 std::shared_ptr<sigrok::Device> device, PyObject *dict)
554 {
58aa1f83 555 return $self->create_output(device,
3b161085 556 dict_to_map_options(dict, $self->options()));
f7740954
ML
557 }
558}
559
560%pythoncode
561{
562 def _OutputFormat_create_output(self, device, **kwargs):
563 return self._create_output_kwargs(device, kwargs)
564
565 OutputFormat.create_output = _OutputFormat_create_output
566}
567
568/* Support config_set() with Python input types. */
569%extend sigrok::Configurable
570{
571 void config_set(const ConfigKey *key, PyObject *input)
572 {
573 $self->config_set(key, python_to_variant_by_key(input, key));
574 }
575}