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