]> sigrok.org Git - libsigrok.git/blob - bindings/python/sigrok/core/classes.i
output/csv: use intermediate time_t var, silence compiler warning
[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 /* Use the same typemap above for Glib::VariantContainerBase */
116 %apply Glib::VariantBase { Glib::VariantContainerBase }
117
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
127     $1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
128         auto gstate = PyGILState_Ensure();
129
130         auto log_obj = SWIG_NewPointerObj(
131                 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
132
133         auto string_obj = string_to_python(message.c_str());
134
135         auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
136
137         auto result = PyObject_CallObject($input, arglist);
138
139         Py_XDECREF(arglist);
140         Py_XDECREF(log_obj);
141         Py_XDECREF(string_obj);
142
143         bool completed = !PyErr_Occurred();
144
145         if (!completed)
146             PyErr_Print();
147
148         bool valid_result = (completed && result == Py_None);
149
150         Py_XDECREF(result);
151
152         if (completed && !valid_result)
153         {
154             PyErr_SetString(PyExc_TypeError,
155                 "Log callback did not return None");
156             PyErr_Print();
157         }
158
159         PyGILState_Release(gstate);
160
161         if (!valid_result)
162             throw sigrok::Error(SR_ERR);
163     };
164
165     Py_XINCREF($input);
166 }
167
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
180         const auto result = PyObject_CallObject($input, nullptr);
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
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
224         auto result = PyObject_CallObject($input, arglist);
225
226         Py_XDECREF(arglist);
227         Py_XDECREF(device_obj);
228         Py_XDECREF(packet_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                 "Datafeed 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 /* 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     }
268     std::shared_ptr<sigrok::Analog> _payload_analog()
269     {
270         return dynamic_pointer_cast<sigrok::Analog>($self->payload());
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()
289         elif self.type == PacketType.ANALOG:
290             return self._payload_analog()
291         else:
292             return None
293
294     payload = property(_payload)
295 }
296 }
297
298 %{
299
300 #include "libsigrokcxx/libsigrokcxx.hpp"
301
302 /* Convert from a Python dict to a std::map<std::string, std::string> */
303 std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
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)) {
314         if (!string_check(py_key))
315             throw sigrok::Error(SR_ERR_ARG);
316         if (!string_check(py_value))
317             throw sigrok::Error(SR_ERR_ARG);
318         auto key = string_from_python(py_key);
319         auto value = string_from_python(py_value);
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. */
327 Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
328 {
329     enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
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));
335     else if (type == SR_T_STRING && string_check(input))
336         return Glib::Variant<Glib::ustring>::create(string_from_python(input));
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));
343     else if (type == SR_T_UINT32 && PyInt_Check(input))
344         return Glib::Variant<guint32>::create(PyInt_AsLong(input));
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))) {
349           const std::vector<guint64> v = {(guint64)PyInt_AsLong(numObj), (guint64)PyInt_AsLong(denomObj)};
350           return Glib::Variant< std::vector<guint64> >::create(v);
351         }
352     }
353     throw sigrok::Error(SR_ERR_ARG);
354 }
355
356 /* Convert from a Python type to Glib::Variant, according to Option data type. */
357 Glib::VariantBase python_to_variant_by_option(PyObject *input,
358     std::shared_ptr<sigrok::Option> option)
359 {
360     GVariantType *type = option->default_value().get_type().gobj();
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));
366     else if (type == G_VARIANT_TYPE_STRING && string_check(input))
367         return Glib::Variant<Glib::ustring>::create(string_from_python(input));
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));
374     else if (type == G_VARIANT_TYPE_UINT32 && PyInt_Check(input))
375         return Glib::Variant<guint32>::create(PyInt_AsLong(input));
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> */
381 std::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)) {
393         if (!string_check(py_key))
394             throw sigrok::Error(SR_ERR_ARG);
395         auto key = string_from_python(py_key);
396         auto value = python_to_variant_by_option(py_value, options[key]);
397         output[key] = value;
398     }
399
400     return output;
401 }
402
403 %}
404
405 /* Ignore these methods, we will override them below. */
406 %ignore sigrok::Analog::data;
407 %ignore sigrok::Logic::data;
408 %ignore sigrok::Driver::scan;
409 %ignore sigrok::InputFormat::create_input;
410 %ignore sigrok::OutputFormat::create_output;
411
412 %include "doc_start.i"
413
414 %define %attributevector(Class, Type, Name, Get)
415 %rename(_ ## Get) sigrok::Class::Get;
416 %extend sigrok::Class
417 {
418 %pythoncode
419 {
420   Name = property(_ ## Get)
421 }
422 }
423 %enddef
424
425 %define %attributemap(Class, Type, Name, Get)
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 }
434 %enddef
435
436 %define %enumextras(Class)
437 %extend sigrok::Class
438 {
439   long __hash__()
440   {
441     return (long) $self;
442   }
443
444   std::string __str__()
445   {
446     return $self->name();
447   }
448
449   std::string __repr__()
450   {
451     return "Class." + $self->name();
452   }
453
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 }
463 %enddef
464
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         {
481             if (!string_check(py_key))
482                 throw sigrok::Error(SR_ERR_ARG);
483             auto key = sigrok::ConfigKey::get_by_identifier(string_from_python(py_key));
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
500 /* Support InputFormat.create_input() with keyword arguments. */
501 %extend sigrok::InputFormat
502 {
503     std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
504     {
505         return $self->create_input(
506             dict_to_map_options(dict, $self->options()));
507     }
508 }
509
510 %pythoncode
511 {
512     def _InputFormat_create_input(self, **kwargs):
513         return self._create_input(kwargs)
514
515     InputFormat.create_input = _InputFormat_create_input
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     {
524         return $self->create_output(device,
525             dict_to_map_options(dict, $self->options()));
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 }
545
546 /* Return NumPy array from Analog::data(). */
547 %extend sigrok::Analog
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 }
565
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
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 }
603
604 %include "doc_end.i"