]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
python: Add override for Context.create_logic_packet()
[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 libsigrokcxx 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 "config.h"
49
50 #include <stdio.h>
51 #include <pygobject.h>
52 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
53 #include <numpy/arrayobject.h>
54
55 PyObject *PyGObject_lib;
56 PyObject *GLib;
57
58 #if PYGOBJECT_FLAGS_SIGNED
59 typedef gint pyg_flags_type;
60 #else
61 typedef guint pyg_flags_type;
62 #endif
63
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
74 %}
75
76 %init %{
77     PyGObject_lib = pygobject_init(-1, -1, -1);
78     if (!PyGObject_lib)
79         fprintf(stderr, "pygobject initialization failed.\n");
80     GLib = PyImport_ImportModule("gi.repository.GLib");
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");
87 #if PY_VERSION_HEX >= 0x03000000
88         return nullptr;
89 #else
90         return;
91 #endif
92     }
93     import_array();
94 %}
95
96 %include "../../../swig/templates.i"
97
98 /* Map file objects to file descriptors. */
99 %typecheck(SWIG_TYPECHECK_POINTER) int fd {
100     $1 = (PyObject_AsFileDescriptor($input) != -1);
101 }
102
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,
110         const_cast<char *>("unpack"), nullptr);
111     Py_XDECREF(variant);
112     g_free(value);
113 }
114
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
124     $1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
125         auto gstate = PyGILState_Ensure();
126
127         auto log_obj = SWIG_NewPointerObj(
128                 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
129
130         auto string_obj = string_to_python(message.c_str());
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);
139
140         bool completed = !PyErr_Occurred();
141
142         if (!completed)
143             PyErr_Print();
144
145         bool valid_result = (completed && result == Py_None);
146
147         Py_XDECREF(result);
148
149         if (completed && !valid_result)
150         {
151             PyErr_SetString(PyExc_TypeError,
152                 "Log callback did not return None");
153             PyErr_Print();
154         }
155
156         PyGILState_Release(gstate);
157
158         if (!valid_result)
159             throw sigrok::Error(SR_ERR);
160     };
161
162     Py_XINCREF($input);
163 }
164
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
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);
226
227         bool completed = !PyErr_Occurred();
228
229         if (!completed)
230             PyErr_Print();
231
232         bool valid_result = (completed && result == Py_None);
233
234         Py_XDECREF(result);
235
236         if (completed && !valid_result)
237         {
238             PyErr_SetString(PyExc_TypeError,
239                 "Datafeed callback did not return None");
240             PyErr_Print();
241         }
242
243         PyGILState_Release(gstate);
244
245         if (!valid_result)
246             throw sigrok::Error(SR_ERR);
247     };
248
249     Py_XINCREF($input);
250 }
251
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     }
265     std::shared_ptr<sigrok::Analog> _payload_analog()
266     {
267         return dynamic_pointer_cast<sigrok::Analog>($self->payload());
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()
286         elif self.type == PacketType.ANALOG:
287             return self._payload_analog()
288         else:
289             return None
290
291     payload = property(_payload)
292 }
293 }
294
295 %{
296
297 #include "libsigrokcxx/libsigrokcxx.hpp"
298
299 /* Convert from a Python dict to a std::map<std::string, std::string> */
300 std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
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)) {
311         if (!string_check(py_key))
312             throw sigrok::Error(SR_ERR_ARG);
313         if (!string_check(py_value))
314             throw sigrok::Error(SR_ERR_ARG);
315         auto key = string_from_python(py_key);
316         auto value = string_from_python(py_value);
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. */
324 Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
325 {
326     enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
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));
332     else if (type == SR_T_STRING && string_check(input))
333         return Glib::Variant<Glib::ustring>::create(string_from_python(input));
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
344 /* Convert from a Python type to Glib::Variant, according to Option data type. */
345 Glib::VariantBase python_to_variant_by_option(PyObject *input,
346     std::shared_ptr<sigrok::Option> option)
347 {
348     GVariantType *type = option->default_value().get_type().gobj();
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));
354     else if (type == G_VARIANT_TYPE_STRING && string_check(input))
355         return Glib::Variant<Glib::ustring>::create(string_from_python(input));
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> */
367 std::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)) {
379         if (!string_check(py_key))
380             throw sigrok::Error(SR_ERR_ARG);
381         auto key = string_from_python(py_key);
382         auto value = python_to_variant_by_option(py_value, options[key]);
383         output[key] = value;
384     }
385
386     return output;
387 }
388
389 %}
390
391 /* Ignore these methods, we will override them below. */
392 %ignore sigrok::Analog::data;
393 %ignore sigrok::Logic::data;
394 %ignore sigrok::Driver::scan;
395 %ignore sigrok::InputFormat::create_input;
396 %ignore sigrok::OutputFormat::create_output;
397
398 %include "doc_start.i"
399
400 %define %attributevector(Class, Type, Name, Get)
401 %rename(_ ## Get) sigrok::Class::Get;
402 %extend sigrok::Class
403 {
404 %pythoncode
405 {
406   Name = property(_ ## Get)
407 }
408 }
409 %enddef
410
411 %define %attributemap(Class, Type, Name, Get)
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 }
420 %enddef
421
422 %define %enumextras(Class)
423 %extend sigrok::Class
424 {
425   long __hash__()
426   {
427     return (long) $self;
428   }
429
430   std::string __str__()
431   {
432     return $self->name();
433   }
434
435   std::string __repr__()
436   {
437     return "Class." + $self->name();
438   }
439
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 }
449 %enddef
450
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         {
467             if (!string_check(py_key))
468                 throw sigrok::Error(SR_ERR_ARG);
469             auto key = sigrok::ConfigKey::get_by_identifier(string_from_python(py_key));
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
486 /* Support InputFormat.create_input() with keyword arguments. */
487 %extend sigrok::InputFormat
488 {
489     std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
490     {
491         return $self->create_input(
492             dict_to_map_options(dict, $self->options()));
493     }
494 }
495
496 %pythoncode
497 {
498     def _InputFormat_create_input(self, **kwargs):
499         return self._create_input(kwargs)
500
501     InputFormat.create_input = _InputFormat_create_input
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     {
510         return $self->create_output(device,
511             dict_to_map_options(dict, $self->options()));
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 }
531
532 /* Return NumPy array from Analog::data(). */
533 %extend sigrok::Analog
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 }
551
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
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 }
589
590 %include "doc_end.i"