]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
python: Return correct PacketPayload subclasses from Packet.payload()
[libsigrok.git] / bindings / python / sigrok / core / classes.i
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
20 %define DOCSTRING
21 "@mainpage API Reference
22
23 Introduction
24 ------------
25
26 The pysigrok API provides an object-oriented Python interface to the
27 functionality in libsigrok. It is built on top of the sigrok++ C++ API.
28
29 Getting started
30 ---------------
31
32 Usage of the pysigrok API needs to begin with a call to Context.create().
33 This will create the global libsigrok context and returns a Context object.
34 Methods on this object provide access to the hardware drivers, input and output
35 formats supported by the library, as well as means of creating other objects
36 such as sessions and triggers.
37
38 Error handling
39 --------------
40
41 When any libsigrok C API call returns an error, an Error exception is raised,
42 which provides access to the error code and description."
43 %enddef
44
45 %module(docstring=DOCSTRING) classes
46
47 %{
48 #include <pygobject.h>
49
50 PyObject *GLib;
51 PyTypeObject *IOChannel;
52 PyTypeObject *PollFD;
53
54 #include "config.h"
55
56 #if PYGOBJECT_FLAGS_SIGNED
57 typedef gint pyg_flags_type;
58 #else
59 typedef guint pyg_flags_type;
60 #endif
61
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 {
100     pyg_flags_type flags;
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");
108     pyg_flags_type flags;
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");
133     pyg_flags_type flags;
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
176         bool completed = !PyErr_Occurred();
177
178         if (!completed)
179             PyErr_Print();
180
181         bool valid_result = (completed && PyBool_Check(result));
182
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);
191
192         Py_XDECREF(result);
193
194         PyGILState_Release(gstate);
195
196         if (!valid_result)
197             throw sigrok::Error(SR_ERR);
198
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);
229
230         bool completed = !PyErr_Occurred();
231
232         if (!completed)
233             PyErr_Print();
234
235         bool valid_result = (completed && result == Py_None);
236
237         Py_XDECREF(result);
238
239         if (completed && !valid_result)
240         {
241             PyErr_SetString(PyExc_TypeError,
242                 "Log callback did not return None");
243             PyErr_Print();
244         }
245
246         PyGILState_Release(gstate);
247
248         if (!valid_result)
249             throw sigrok::Error(SR_ERR);
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);
283
284         bool completed = !PyErr_Occurred();
285
286         if (!completed)
287             PyErr_Print();
288
289         bool valid_result = (completed && result == Py_None);
290
291         Py_XDECREF(result);
292
293         if (completed && !valid_result)
294         {
295             PyErr_SetString(PyExc_TypeError,
296                 "Datafeed callback did not return None");
297             PyErr_Print();
298         }
299
300         PyGILState_Release(gstate);
301
302         if (!valid_result)
303             throw sigrok::Error(SR_ERR);
304     };
305
306     Py_XINCREF($input);
307 }
308
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
352 %{
353
354 #include "libsigrok/libsigrok.hpp"
355
356 /* Convert from a Python dict to a std::map<std::string, std::string> */
357 std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
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. */
381 Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
382 {
383     enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
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))
390         return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
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
401 /* Convert from a Python type to Glib::Variant, according to Option data type. */
402 Glib::VariantBase python_to_variant_by_option(PyObject *input,
403     std::shared_ptr<sigrok::Option> option)
404 {
405     GVariantType *type = option->default_value().get_type().gobj();
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))
412         return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
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> */
424 std::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
446 %}
447
448 /* Ignore these methods, we will override them below. */
449 %ignore sigrok::Driver::scan;
450 %ignore sigrok::InputFormat::create_input;
451 %ignore sigrok::OutputFormat::create_output;
452
453 %include "doc.i"
454
455 %define %attributevector(Class, Type, Name, Get)
456 %rename(_ ## Get) sigrok::Class::Get;
457 %extend sigrok::Class
458 {
459 %pythoncode
460 {
461   Name = property(_ ## Get)
462 }
463 }
464 %enddef
465
466 %define %attributemap(Class, Type, Name, Get)
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 }
475 %enddef
476
477 %define %enumextras(Class)
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 }
494 %enddef
495
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);
514             auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
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
531 /* Support InputFormat.create_input() with keyword arguments. */
532 %extend sigrok::InputFormat
533 {
534     std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
535     {
536         return $self->create_input(
537             dict_to_map_options(dict, $self->options()));
538     }
539 }
540
541 %pythoncode
542 {
543     def _InputFormat_create_input(self, **kwargs):
544         return self._create_input(kwargs)
545
546     InputFormat.create_input = _InputFormat_create_input
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     {
555         return $self->create_output(device,
556             dict_to_map_options(dict, $self->options()));
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 }