Implement Ruby bindings on top of SWIG/C++ bindings.
This commit is contained in:
parent
0441038e2f
commit
27d44cf6e0
45
Makefile.am
45
Makefile.am
|
@ -654,6 +654,51 @@ CLEAN_EXTRA += python-clean
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BINDINGS_RUBY
|
||||||
|
|
||||||
|
RDIR = bindings/ruby
|
||||||
|
RDOC = $(RDIR)/doc.i
|
||||||
|
RWRAP = $(RDIR)/classes_wrap.cpp
|
||||||
|
ROBJ = $(RWRAP:.cpp=.o)
|
||||||
|
REXT = $(RDIR)/sigrok.so
|
||||||
|
|
||||||
|
$(RDOC): $(srcdir)/bindings/swig/doc.py $(CPPXMLDOC)
|
||||||
|
$(AM_V_GEN)$(PYTHON) $(srcdir)/bindings/swig/doc.py ruby $(CPPXMLDOC) > $@
|
||||||
|
|
||||||
|
$(RWRAP): $(RDIR)/classes.i $(RDOC) \
|
||||||
|
bindings/swig/classes.i bindings/swig/templates.i \
|
||||||
|
bindings/swig/enums.i
|
||||||
|
$(AM_V_GEN)$(SWIG) -ruby -c++ -Ibindings -Ibindings/cxx/include $(swig_defs) -o $@ $<
|
||||||
|
|
||||||
|
$(ROBJ): $(RWRAP) \
|
||||||
|
$(library_include_HEADERS) \
|
||||||
|
$(nodist_library_include_HEADERS) \
|
||||||
|
$(bindings_cxx_libsigrokcxx_la_include_HEADERS) \
|
||||||
|
$(nodist_bindings_cxx_libsigrokcxx_la_include_HEADERS)
|
||||||
|
$(AM_V_CXX)$(CXX) $(RBSIGROK_CFLAGS) -I. -Iinclude -Ibindings/cxx/include -fPIC -o $@ -c $<
|
||||||
|
|
||||||
|
$(REXT): $(ROBJ) @ORDER@ bindings/cxx/libsigrokcxx.la
|
||||||
|
$(AM_V_CXXLD)$(CXX) -shared -std=c++11 -o $@ $< -lsigrokcxx -Lbindings/cxx/.libs $(RBSIGROK_LIBS)
|
||||||
|
|
||||||
|
ruby-build: $(REXT)
|
||||||
|
|
||||||
|
ruby-install: $(REXT)
|
||||||
|
$(INSTALL) -d $(prefix)/$(RBSIGROK_EXTDIR)
|
||||||
|
$(INSTALL) $< $(prefix)/$(RBSIGROK_EXTDIR)
|
||||||
|
|
||||||
|
ruby-clean:
|
||||||
|
-$(AM_V_at)rm -fr $(RDIR)/doc
|
||||||
|
-$(AM_V_at)rm $(REXT) $(ROBJ) $(RWRAP) $(RDOC)
|
||||||
|
|
||||||
|
ruby-doc: $(RWRAP)
|
||||||
|
$(AM_V_at)yard doc -o $(RDIR)/doc $<
|
||||||
|
|
||||||
|
BUILD_EXTRA += ruby-build
|
||||||
|
INSTALL_EXTRA += ruby-install
|
||||||
|
CLEAN_EXTRA += ruby-clean
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
if BINDINGS_JAVA
|
if BINDINGS_JAVA
|
||||||
|
|
||||||
JDIR = bindings/java
|
JDIR = bindings/java
|
||||||
|
|
7
README
7
README
|
@ -71,6 +71,13 @@ Requirements for the Python bindings:
|
||||||
- graphviz (optional, only needed for the Python API docs)
|
- graphviz (optional, only needed for the Python API docs)
|
||||||
- doxypy (optional, only needed for the Python API docs)
|
- doxypy (optional, only needed for the Python API docs)
|
||||||
|
|
||||||
|
Requirements for the Ruby bindings:
|
||||||
|
|
||||||
|
- libsigrokcxx >= 0.3.0 (the libsigrok C++ bindings, see above)
|
||||||
|
- Ruby >= 1.9.3 (including development files!)
|
||||||
|
- SWIG >= 3.0.8
|
||||||
|
- YARD (optional, only needed for the Ruby API docs)
|
||||||
|
|
||||||
Requirements for the Java bindings:
|
Requirements for the Java bindings:
|
||||||
|
|
||||||
- libsigrokcxx >= 0.3.0 (the libsigrok C++ bindings, see above)
|
- libsigrokcxx >= 0.3.0 (the libsigrok C++ bindings, see above)
|
||||||
|
|
|
@ -0,0 +1,428 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Aurelien Jacobs <aurel@gnuage.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
%define DOCSTRING
|
||||||
|
"
|
||||||
|
= Introduction
|
||||||
|
|
||||||
|
The sigrok Ruby API provides an object-oriented Ruby interface to the
|
||||||
|
functionality in libsigrok. It is built on top of the libsigrokcxx C++ API.
|
||||||
|
|
||||||
|
= Getting started
|
||||||
|
|
||||||
|
Usage of the sigrok Ruby API needs to begin with a call to Context.create().
|
||||||
|
This will create the global libsigrok context and returns a Context object.
|
||||||
|
Methods on this object provide access to the hardware drivers, input and output
|
||||||
|
formats supported by the library, as well as means of creating other objects
|
||||||
|
such as sessions and triggers.
|
||||||
|
|
||||||
|
= Error handling
|
||||||
|
|
||||||
|
When any libsigrok C API call returns an error, an Error exception is raised,
|
||||||
|
which provides access to the error code and description."
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%module(docstring=DOCSTRING) sigrok
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <glibmm.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%include "../swig/templates.i"
|
||||||
|
|
||||||
|
%{
|
||||||
|
static const char *string_from_ruby(VALUE obj)
|
||||||
|
{
|
||||||
|
switch (TYPE(obj)) {
|
||||||
|
case T_STRING:
|
||||||
|
return StringValueCStr(obj);
|
||||||
|
case T_SYMBOL:
|
||||||
|
return rb_id2name(SYM2ID(obj));
|
||||||
|
default:
|
||||||
|
throw sigrok::Error(SR_ERR_ARG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert from Glib::Variant to native Ruby types. */
|
||||||
|
static VALUE variant_to_ruby(Glib::VariantBase variant)
|
||||||
|
{
|
||||||
|
if (variant.is_of_type(Glib::VARIANT_TYPE_BOOL)) {
|
||||||
|
return Glib::VariantBase::cast_dynamic< Glib::Variant<bool> >(variant).get() ? Qtrue : Qfalse;
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_BYTE)) {
|
||||||
|
return UINT2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<unsigned char> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_INT16)) {
|
||||||
|
return INT2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<gint16> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_UINT16)) {
|
||||||
|
return UINT2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<guint16> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_INT32)) {
|
||||||
|
return INT2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<gint32> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_UINT32)) {
|
||||||
|
return UINT2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<guint32> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_INT64)) {
|
||||||
|
return LL2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<gint64> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_UINT64)) {
|
||||||
|
return ULL2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<guint64> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_DOUBLE)) {
|
||||||
|
return DBL2NUM(Glib::VariantBase::cast_dynamic< Glib::Variant<double> >(variant).get());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_STRING)) {
|
||||||
|
auto str = Glib::VariantBase::cast_dynamic< Glib::Variant<std::string> >(variant).get();
|
||||||
|
return rb_str_new(str.c_str(), str.length());
|
||||||
|
} else if (variant.is_of_type(Glib::VARIANT_TYPE_VARIANT)) {
|
||||||
|
auto var = Glib::VariantBase::cast_dynamic< Glib::Variant<Glib::VariantBase> >(variant).get();
|
||||||
|
return variant_to_ruby(var);
|
||||||
|
} else if (variant.is_container()) {
|
||||||
|
Glib::VariantContainerBase container = Glib::VariantBase::cast_dynamic< Glib::VariantContainerBase > (variant);
|
||||||
|
gsize count = container.get_n_children();
|
||||||
|
if (container.is_of_type(Glib::VARIANT_TYPE_DICTIONARY)) {
|
||||||
|
VALUE hash = rb_hash_new();
|
||||||
|
for (gsize i = 0; i < count; i++) {
|
||||||
|
Glib::VariantContainerBase entry = Glib::VariantBase::cast_dynamic< Glib::VariantContainerBase > (container.get_child(i));
|
||||||
|
VALUE key = variant_to_ruby(entry.get_child(0));
|
||||||
|
VALUE val = variant_to_ruby(entry.get_child(1));
|
||||||
|
rb_hash_aset(hash, key, val);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
} else if (container.is_of_type(Glib::VARIANT_TYPE_ARRAY) ||
|
||||||
|
container.is_of_type(Glib::VARIANT_TYPE_TUPLE)) {
|
||||||
|
VALUE array = rb_ary_new2(count);
|
||||||
|
for (gsize i = 0; i < count; i++) {
|
||||||
|
VALUE val = variant_to_ruby(container.get_child(i));
|
||||||
|
rb_ary_store(array, i, val);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SWIG_exception(SWIG_TypeError, ("TODO: GVariant(" + variant.get_type().get_string() + ") -> Ruby").c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
/* Map from Glib::Variant to native Ruby types. */
|
||||||
|
%typemap(out) Glib::VariantBase {
|
||||||
|
$result = variant_to_ruby($1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map from Glib::VariantContainer to native Ruby types. */
|
||||||
|
%typemap(out) Glib::VariantContainerBase {
|
||||||
|
$result = variant_to_ruby($1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map from callable Ruby Proc to LogCallbackFunction */
|
||||||
|
%typemap(in) sigrok::LogCallbackFunction {
|
||||||
|
if (!rb_obj_is_proc($input))
|
||||||
|
SWIG_exception(SWIG_TypeError, "Expected a callable Ruby object");
|
||||||
|
|
||||||
|
std::shared_ptr<VALUE> proc(new VALUE($input), rb_gc_unregister_address);
|
||||||
|
rb_gc_register_address(proc.get());
|
||||||
|
|
||||||
|
$1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
|
||||||
|
VALUE log_obj = SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
|
||||||
|
|
||||||
|
VALUE string_obj = rb_external_str_new_with_enc(message.c_str(), message.length(), rb_utf8_encoding());
|
||||||
|
|
||||||
|
VALUE args = rb_ary_new_from_args(2, log_obj, string_obj);
|
||||||
|
rb_proc_call(*proc.get(), args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map from callable Ruby Proc to SessionStoppedCallback */
|
||||||
|
%typemap(in) sigrok::SessionStoppedCallback {
|
||||||
|
if (!rb_obj_is_proc($input))
|
||||||
|
SWIG_exception(SWIG_TypeError, "Expected a callable Ruby object");
|
||||||
|
|
||||||
|
std::shared_ptr<VALUE> proc(new VALUE($input), rb_gc_unregister_address);
|
||||||
|
rb_gc_register_address(proc.get());
|
||||||
|
|
||||||
|
$1 = [=] () {
|
||||||
|
rb_proc_call(*proc.get(), rb_ary_new());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map from callable Ruby Proc to DatafeedCallbackFunction */
|
||||||
|
%typemap(in) sigrok::DatafeedCallbackFunction {
|
||||||
|
if (!rb_obj_is_proc($input))
|
||||||
|
SWIG_exception(SWIG_TypeError, "Expected a callable Ruby object");
|
||||||
|
|
||||||
|
std::shared_ptr<VALUE> proc(new VALUE($input), rb_gc_unregister_address);
|
||||||
|
rb_gc_register_address(proc.get());
|
||||||
|
|
||||||
|
$1 = [=] (std::shared_ptr<sigrok::Device> device,
|
||||||
|
std::shared_ptr<sigrok::Packet> packet) {
|
||||||
|
VALUE device_obj = SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
|
||||||
|
SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
|
||||||
|
|
||||||
|
VALUE packet_obj = SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
|
||||||
|
SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
|
||||||
|
|
||||||
|
VALUE args = rb_ary_new_from_args(2, device_obj, packet_obj);
|
||||||
|
rb_proc_call(*proc.get(), args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cast PacketPayload pointers to correct subclass type. */
|
||||||
|
%ignore sigrok::Packet::payload;
|
||||||
|
%rename sigrok::Packet::_payload payload;
|
||||||
|
%extend sigrok::Packet
|
||||||
|
{
|
||||||
|
VALUE _payload()
|
||||||
|
{
|
||||||
|
if ($self->type() == sigrok::PacketType::HEADER) {
|
||||||
|
return SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr(new std::shared_ptr<sigrok::Header>(dynamic_pointer_cast<sigrok::Header>($self->payload()))),
|
||||||
|
SWIGTYPE_p_std__shared_ptrT_sigrok__Header_t, SWIG_POINTER_OWN);
|
||||||
|
} else if ($self->type() == sigrok::PacketType::META) {
|
||||||
|
return SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr(new std::shared_ptr<sigrok::Meta>(dynamic_pointer_cast<sigrok::Meta>($self->payload()))),
|
||||||
|
SWIGTYPE_p_std__shared_ptrT_sigrok__Meta_t, SWIG_POINTER_OWN);
|
||||||
|
} else if ($self->type() == sigrok::PacketType::ANALOG) {
|
||||||
|
return SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr(new std::shared_ptr<sigrok::Analog>(dynamic_pointer_cast<sigrok::Analog>($self->payload()))),
|
||||||
|
SWIGTYPE_p_std__shared_ptrT_sigrok__Analog_t, SWIG_POINTER_OWN);
|
||||||
|
} else if ($self->type() == sigrok::PacketType::LOGIC) {
|
||||||
|
return SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr(new std::shared_ptr<sigrok::Logic>(dynamic_pointer_cast<sigrok::Logic>($self->payload()))),
|
||||||
|
SWIGTYPE_p_std__shared_ptrT_sigrok__Logic_t, SWIG_POINTER_OWN);
|
||||||
|
} else {
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%{
|
||||||
|
|
||||||
|
#include "libsigrokcxx/libsigrokcxx.hpp"
|
||||||
|
|
||||||
|
/* Convert from a Ruby type to Glib::Variant, according to config key data type. */
|
||||||
|
Glib::VariantBase ruby_to_variant_by_key(VALUE input, const sigrok::ConfigKey *key)
|
||||||
|
{
|
||||||
|
enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
|
||||||
|
|
||||||
|
if (type == SR_T_UINT64 && RB_TYPE_P(input, T_FIXNUM))
|
||||||
|
return Glib::Variant<guint64>::create(NUM2ULL(input));
|
||||||
|
if (type == SR_T_UINT64 && RB_TYPE_P(input, T_BIGNUM))
|
||||||
|
return Glib::Variant<guint64>::create(NUM2ULL(input));
|
||||||
|
else if (type == SR_T_STRING && RB_TYPE_P(input, T_STRING))
|
||||||
|
return Glib::Variant<Glib::ustring>::create(string_from_ruby(input));
|
||||||
|
else if (type == SR_T_STRING && RB_TYPE_P(input, T_SYMBOL))
|
||||||
|
return Glib::Variant<Glib::ustring>::create(string_from_ruby(input));
|
||||||
|
else if (type == SR_T_BOOL && RB_TYPE_P(input, T_TRUE))
|
||||||
|
return Glib::Variant<bool>::create(true);
|
||||||
|
else if (type == SR_T_BOOL && RB_TYPE_P(input, T_FALSE))
|
||||||
|
return Glib::Variant<bool>::create(false);
|
||||||
|
else if (type == SR_T_FLOAT && RB_TYPE_P(input, T_FLOAT))
|
||||||
|
return Glib::Variant<double>::create(RFLOAT_VALUE(input));
|
||||||
|
else if (type == SR_T_INT32 && RB_TYPE_P(input, T_FIXNUM))
|
||||||
|
return Glib::Variant<gint32>::create(NUM2INT(input));
|
||||||
|
else
|
||||||
|
throw sigrok::Error(SR_ERR_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert from a Ruby type to Glib::Variant, according to Option data type. */
|
||||||
|
Glib::VariantBase ruby_to_variant_by_option(VALUE input, std::shared_ptr<sigrok::Option> option)
|
||||||
|
{
|
||||||
|
Glib::VariantBase variant = option->default_value();
|
||||||
|
|
||||||
|
if (variant.is_of_type(Glib::VARIANT_TYPE_UINT64) && RB_TYPE_P(input, T_FIXNUM))
|
||||||
|
return Glib::Variant<guint64>::create(NUM2ULL(input));
|
||||||
|
else if (variant.is_of_type(Glib::VARIANT_TYPE_UINT64) && RB_TYPE_P(input, T_BIGNUM))
|
||||||
|
return Glib::Variant<guint64>::create(NUM2ULL(input));
|
||||||
|
else if (variant.is_of_type(Glib::VARIANT_TYPE_STRING) && RB_TYPE_P(input, T_STRING))
|
||||||
|
return Glib::Variant<Glib::ustring>::create(string_from_ruby(input));
|
||||||
|
else if (variant.is_of_type(Glib::VARIANT_TYPE_STRING) && RB_TYPE_P(input, T_SYMBOL))
|
||||||
|
return Glib::Variant<Glib::ustring>::create(string_from_ruby(input));
|
||||||
|
else if (variant.is_of_type(Glib::VARIANT_TYPE_BOOL) && RB_TYPE_P(input, T_TRUE))
|
||||||
|
return Glib::Variant<bool>::create(true);
|
||||||
|
else if (variant.is_of_type(Glib::VARIANT_TYPE_BOOL) && RB_TYPE_P(input, T_FALSE))
|
||||||
|
return Glib::Variant<bool>::create(false);
|
||||||
|
else if (variant.is_of_type(Glib::VARIANT_TYPE_DOUBLE) && RB_TYPE_P(input, T_FLOAT))
|
||||||
|
return Glib::Variant<double>::create(RFLOAT_VALUE(input));
|
||||||
|
else if (variant.is_of_type(Glib::VARIANT_TYPE_INT32) && RB_TYPE_P(input, T_FIXNUM))
|
||||||
|
return Glib::Variant<gint32>::create(NUM2INT(input));
|
||||||
|
else
|
||||||
|
throw sigrok::Error(SR_ERR_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hash_to_map_options_params {
|
||||||
|
std::map<std::string, std::shared_ptr<sigrok::Option> > options;
|
||||||
|
std::map<std::string, Glib::VariantBase> output;
|
||||||
|
};
|
||||||
|
|
||||||
|
int convert_option(VALUE key, VALUE val, VALUE in) {
|
||||||
|
struct hash_to_map_options_params *params;
|
||||||
|
params = (struct hash_to_map_options_params *)in;
|
||||||
|
|
||||||
|
auto k = string_from_ruby(key);
|
||||||
|
auto v = ruby_to_variant_by_option(val, params->options[k]);
|
||||||
|
params->output[k] = v;
|
||||||
|
|
||||||
|
return ST_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert from a Ruby hash to a std::map<std::string, Glib::VariantBase> */
|
||||||
|
std::map<std::string, Glib::VariantBase> hash_to_map_options(VALUE hash,
|
||||||
|
std::map<std::string, std::shared_ptr<sigrok::Option> > options)
|
||||||
|
{
|
||||||
|
if (!RB_TYPE_P(hash, T_HASH))
|
||||||
|
throw sigrok::Error(SR_ERR_ARG);
|
||||||
|
|
||||||
|
struct hash_to_map_options_params params = { options };
|
||||||
|
rb_hash_foreach(hash, (int (*)(ANYARGS))convert_option, (VALUE)¶ms);
|
||||||
|
|
||||||
|
return params.output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert_option_by_key(VALUE key, VALUE val, VALUE in) {
|
||||||
|
std::map<const sigrok::ConfigKey *, Glib::VariantBase> *options;
|
||||||
|
options = (std::map<const sigrok::ConfigKey *, Glib::VariantBase> *)in;
|
||||||
|
|
||||||
|
auto k = sigrok::ConfigKey::get_by_identifier(string_from_ruby(key));
|
||||||
|
auto v = ruby_to_variant_by_key(val, k);
|
||||||
|
(*options)[k] = v;
|
||||||
|
|
||||||
|
return ST_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
/* Ignore these methods, we will override them below. */
|
||||||
|
%ignore sigrok::Analog::data;
|
||||||
|
%ignore sigrok::Driver::scan;
|
||||||
|
%ignore sigrok::Input::send;
|
||||||
|
%ignore sigrok::InputFormat::create_input;
|
||||||
|
%ignore sigrok::OutputFormat::create_output;
|
||||||
|
|
||||||
|
%include "doc.i"
|
||||||
|
|
||||||
|
%define %attributevector(Class, Type, Name, Get)
|
||||||
|
%alias sigrok::Class::_ ## Get #Name;
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%define %attributemap(Class, Type, Name, Get)
|
||||||
|
%alias sigrok::Class::_ ## Get #Name;
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%define %enumextras(Class)
|
||||||
|
%extend sigrok::Class
|
||||||
|
{
|
||||||
|
VALUE to_s()
|
||||||
|
{
|
||||||
|
std::string str = $self->name();
|
||||||
|
return rb_external_str_new_with_enc(str.c_str(), str.length(), rb_utf8_encoding());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(void *other)
|
||||||
|
{
|
||||||
|
return (long) $self == (long) other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%include "../swig/classes.i"
|
||||||
|
|
||||||
|
/* Replace the original Driver.scan with a keyword arguments version. */
|
||||||
|
%rename sigrok::Driver::_scan scan;
|
||||||
|
%extend sigrok::Driver
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan(VALUE kwargs = rb_hash_new())
|
||||||
|
{
|
||||||
|
if (!RB_TYPE_P(kwargs, T_HASH))
|
||||||
|
throw sigrok::Error(SR_ERR_ARG);
|
||||||
|
|
||||||
|
std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
|
||||||
|
rb_hash_foreach(kwargs, (int (*)(ANYARGS))convert_option_by_key, (VALUE)&options);
|
||||||
|
|
||||||
|
return $self->scan(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Support Input.send() with string argument. */
|
||||||
|
%rename sigrok::Input::_send send;
|
||||||
|
%extend sigrok::Input
|
||||||
|
{
|
||||||
|
void _send(VALUE data)
|
||||||
|
{
|
||||||
|
data = StringValue(data);
|
||||||
|
return $self->send(RSTRING_PTR(data), RSTRING_LEN(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Support InputFormat.create_input() with keyword arguments. */
|
||||||
|
%rename sigrok::InputFormat::_create_input create_input;
|
||||||
|
%extend sigrok::InputFormat
|
||||||
|
{
|
||||||
|
std::shared_ptr<sigrok::Input> _create_input(VALUE hash = rb_hash_new())
|
||||||
|
{
|
||||||
|
return $self->create_input(hash_to_map_options(hash, $self->options()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Support OutputFormat.create_output() with keyword arguments. */
|
||||||
|
%rename sigrok::OutputFormat::_create_output create_output;
|
||||||
|
%extend sigrok::OutputFormat
|
||||||
|
{
|
||||||
|
std::shared_ptr<sigrok::Output> _create_output(
|
||||||
|
std::shared_ptr<sigrok::Device> device, VALUE hash = rb_hash_new())
|
||||||
|
{
|
||||||
|
return $self->create_output(device,
|
||||||
|
hash_to_map_options(hash, $self->options()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<sigrok::Output> _create_output(string filename,
|
||||||
|
std::shared_ptr<sigrok::Device> device, VALUE hash = rb_hash_new())
|
||||||
|
{
|
||||||
|
return $self->create_output(filename, device,
|
||||||
|
hash_to_map_options(hash, $self->options()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Support config_set() with Ruby input types. */
|
||||||
|
%extend sigrok::Configurable
|
||||||
|
{
|
||||||
|
void config_set(const ConfigKey *key, VALUE input)
|
||||||
|
{
|
||||||
|
$self->config_set(key, ruby_to_variant_by_key(input, key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return Ruby array from Analog::data(). */
|
||||||
|
%rename sigrok::Analog::_data data;
|
||||||
|
%extend sigrok::Analog
|
||||||
|
{
|
||||||
|
VALUE _data()
|
||||||
|
{
|
||||||
|
int num_channels = $self->channels().size();
|
||||||
|
int num_samples = $self->num_samples();
|
||||||
|
float *data = (float *) $self->data_pointer();
|
||||||
|
VALUE channels = rb_ary_new2(num_channels);
|
||||||
|
for(int i = 0; i < num_channels; i++) {
|
||||||
|
VALUE samples = rb_ary_new2(num_samples);
|
||||||
|
for (int j = 0; j < num_samples; j++) {
|
||||||
|
rb_ary_store(samples, j, DBL2NUM(data[i*num_samples+j]));
|
||||||
|
}
|
||||||
|
rb_ary_store(channels, i, samples);
|
||||||
|
}
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,8 @@ for compound in index.findall('compound'):
|
||||||
if brief:
|
if brief:
|
||||||
if language == 'python':
|
if language == 'python':
|
||||||
print('%%feature("docstring") %s "%s";' % (class_name, brief))
|
print('%%feature("docstring") %s "%s";' % (class_name, brief))
|
||||||
|
elif language == 'ruby':
|
||||||
|
print('%%feature("docstring") %s "/* Document-class: %s\\n%s */\\n";' % (class_name, class_name.replace("sigrok", "Sigrok", 1), brief))
|
||||||
elif language == 'java':
|
elif language == 'java':
|
||||||
print('%%typemap(javaclassmodifiers) %s "/** %s */\npublic class"' % (
|
print('%%typemap(javaclassmodifiers) %s "/** %s */\npublic class"' % (
|
||||||
class_name, brief))
|
class_name, brief))
|
||||||
|
@ -73,6 +75,12 @@ for compound in index.findall('compound'):
|
||||||
class_name, member_name, brief)] + [
|
class_name, member_name, brief)] + [
|
||||||
'@param %s %s' % (name, desc)
|
'@param %s %s' % (name, desc)
|
||||||
for name, desc in parameters.items()]) + '";')
|
for name, desc in parameters.items()]) + '";')
|
||||||
|
if language == 'ruby' and kind == 'public-func':
|
||||||
|
print(str.join('\n', [
|
||||||
|
'%%feature("docstring") %s::%s "/* %s' % (
|
||||||
|
class_name, member_name, brief)] + [
|
||||||
|
'@param %s %s' % (name, desc)
|
||||||
|
for name, desc in parameters.items()]) + ' */\\n";')
|
||||||
elif language == 'java' and kind == 'public-func':
|
elif language == 'java' and kind == 'public-func':
|
||||||
print(str.join('\n', [
|
print(str.join('\n', [
|
||||||
'%%javamethodmodifiers %s::%s "/** %s' % (
|
'%%javamethodmodifiers %s::%s "/** %s' % (
|
||||||
|
@ -101,3 +109,6 @@ for compound in index.findall('compound'):
|
||||||
print('%s.%s.__doc__ = """%s"""' % (
|
print('%s.%s.__doc__ = """%s"""' % (
|
||||||
trimmed_name, member_name, brief))
|
trimmed_name, member_name, brief))
|
||||||
print('%}')
|
print('%}')
|
||||||
|
elif language == 'ruby' and constants:
|
||||||
|
for member_name, brief in constants:
|
||||||
|
print('%%feature("docstring") %s::%s "/* %s */\\n";' % (class_name, member_name, brief))
|
||||||
|
|
44
configure.ac
44
configure.ac
|
@ -91,6 +91,7 @@ SR_VAR_OPT_PKG([SR_PKGLIBS], [sr_deps_avail])
|
||||||
SR_PKGLIBS_TESTS=
|
SR_PKGLIBS_TESTS=
|
||||||
SR_PKGLIBS_CXX=
|
SR_PKGLIBS_CXX=
|
||||||
SR_PKGLIBS_PYTHON=
|
SR_PKGLIBS_PYTHON=
|
||||||
|
SR_PKGLIBS_RUBY=
|
||||||
SR_EXTRA_LIBS=
|
SR_EXTRA_LIBS=
|
||||||
|
|
||||||
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
|
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
|
||||||
|
@ -282,6 +283,10 @@ AC_ARG_ENABLE([python],
|
||||||
[AS_HELP_STRING([--enable-python], [build Python bindings [default=yes]])],
|
[AS_HELP_STRING([--enable-python], [build Python bindings [default=yes]])],
|
||||||
[], [enable_python=$enable_bindings])
|
[], [enable_python=$enable_bindings])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([ruby],
|
||||||
|
[AS_HELP_STRING([--enable-ruby], [build Ruby bindings [default=yes]])],
|
||||||
|
[], [enable_ruby=$enable_bindings])
|
||||||
|
|
||||||
AC_ARG_ENABLE([java],
|
AC_ARG_ENABLE([java],
|
||||||
[AS_HELP_STRING([--enable-java], [build Java bindings [default=yes]])],
|
[AS_HELP_STRING([--enable-java], [build Java bindings [default=yes]])],
|
||||||
[], [enable_java=$enable_bindings])
|
[], [enable_java=$enable_bindings])
|
||||||
|
@ -386,6 +391,41 @@ AS_IF([test -z "$sr_python_missing"],
|
||||||
[BINDINGS_PYTHON=$enable_python], [BINDINGS_PYTHON=no])
|
[BINDINGS_PYTHON=$enable_python], [BINDINGS_PYTHON=no])
|
||||||
AM_CONDITIONAL([BINDINGS_PYTHON], [test "x$BINDINGS_PYTHON" = xyes])
|
AM_CONDITIONAL([BINDINGS_PYTHON], [test "x$BINDINGS_PYTHON" = xyes])
|
||||||
|
|
||||||
|
#####################
|
||||||
|
## Ruby bindings ##
|
||||||
|
#####################
|
||||||
|
|
||||||
|
AS_IF([test "x$BINDINGS_CXX" = xyes],
|
||||||
|
[sr_ruby_missing=],
|
||||||
|
[sr_ruby_missing='C++ bindings'])
|
||||||
|
|
||||||
|
AX_RUBY_EXT
|
||||||
|
|
||||||
|
AS_IF([test "x$RUBY" = x],
|
||||||
|
[SR_APPEND([sr_ruby_missing], [', '], ['Ruby'])])
|
||||||
|
|
||||||
|
# Extract major and minor version number of the Ruby interpreter.
|
||||||
|
sr_rbmajor=${RUBY_VERSION%%.*}
|
||||||
|
sr_rbminor=${RUBY_VERSION#*.}
|
||||||
|
sr_rbminor=${sr_rbminor%%.*}
|
||||||
|
|
||||||
|
# The Ruby bindings need Ruby development files.
|
||||||
|
SR_PKG_CHECK([ruby_dev], [SR_PKGLIBS_RUBY],
|
||||||
|
[ruby],
|
||||||
|
[ruby-$sr_rbmajor.$sr_rbminor])
|
||||||
|
|
||||||
|
AS_IF([test "x$sr_have_ruby_dev" != xyes],
|
||||||
|
[SR_APPEND([sr_ruby_missing], [', '], [Headers])])
|
||||||
|
|
||||||
|
# The Ruby bindings use SWIG to generate code.
|
||||||
|
AS_IF([test "x$SWIG" = x],
|
||||||
|
[SR_APPEND([sr_ruby_missing], [', '], [SWIG])])
|
||||||
|
|
||||||
|
AS_IF([test -z "$sr_ruby_missing"],
|
||||||
|
[BINDINGS_RUBY=$enable_ruby], [BINDINGS_RUBY=no])
|
||||||
|
AM_CONDITIONAL([BINDINGS_RUBY], [test "x$BINDINGS_RUBY" = xyes])
|
||||||
|
# AC_SUBST(RUBY_EXT_DLEXT, $RUBY_EXT_DLEXT)
|
||||||
|
|
||||||
####################
|
####################
|
||||||
## Java bindings ##
|
## Java bindings ##
|
||||||
####################
|
####################
|
||||||
|
@ -454,6 +494,7 @@ PKG_CHECK_MODULES([TESTS], [$SR_PKGLIBS_TESTS glib-2.0 $SR_PKGLIBS])
|
||||||
AM_COND_IF([BINDINGS_CXX], [
|
AM_COND_IF([BINDINGS_CXX], [
|
||||||
PKG_CHECK_MODULES([LIBSIGROKCXX], [$SR_PKGLIBS_CXX])
|
PKG_CHECK_MODULES([LIBSIGROKCXX], [$SR_PKGLIBS_CXX])
|
||||||
PKG_CHECK_MODULES([PYSIGROK], [$SR_PKGLIBS_PYTHON $SR_PKGLIBS_CXX])
|
PKG_CHECK_MODULES([PYSIGROK], [$SR_PKGLIBS_PYTHON $SR_PKGLIBS_CXX])
|
||||||
|
PKG_CHECK_MODULES([RBSIGROK], [$SR_PKGLIBS_RUBY $SR_PKGLIBS_CXX], [AC_SUBST(RBSIGROK_EXTDIR, "lib/$($PKG_CONFIG --variable=sitearch $SR_PKGLIBS_RUBY)/$($PKG_CONFIG --variable=RUBY_BASE_NAME $SR_PKGLIBS_RUBY)/vendor_ruby/$($PKG_CONFIG --variable=ruby_version $SR_PKGLIBS_RUBY)")])
|
||||||
])
|
])
|
||||||
|
|
||||||
# Check for specific libusb features, now that we know the CFLAGS.
|
# Check for specific libusb features, now that we know the CFLAGS.
|
||||||
|
@ -490,7 +531,7 @@ m4_define([SR_PREPARE_BINDING_REPORT], [
|
||||||
test -z "$sr_$1_missing" || sr_report_$1=" (missing: $sr_$1_missing)"
|
test -z "$sr_$1_missing" || sr_report_$1=" (missing: $sr_$1_missing)"
|
||||||
test "x$enable_$1" = xyes || sr_report_$1=' (disabled)'
|
test "x$enable_$1" = xyes || sr_report_$1=' (disabled)'
|
||||||
])
|
])
|
||||||
m4_map_args([SR_PREPARE_BINDING_REPORT], [cxx], [python], [java])
|
m4_map_args([SR_PREPARE_BINDING_REPORT], [cxx], [python], [ruby], [java])
|
||||||
|
|
||||||
cat >&AS_MESSAGE_FD <<_EOF
|
cat >&AS_MESSAGE_FD <<_EOF
|
||||||
|
|
||||||
|
@ -531,6 +572,7 @@ Enabled SCPI backends:
|
||||||
Enabled language bindings:
|
Enabled language bindings:
|
||||||
- C++............................. $BINDINGS_CXX$sr_report_cxx
|
- C++............................. $BINDINGS_CXX$sr_report_cxx
|
||||||
- Python.......................... $BINDINGS_PYTHON$sr_report_python
|
- Python.......................... $BINDINGS_PYTHON$sr_report_python
|
||||||
|
- Ruby............................ $BINDINGS_RUBY$sr_report_ruby
|
||||||
- Java............................ $BINDINGS_JAVA$sr_report_java
|
- Java............................ $BINDINGS_JAVA$sr_report_java
|
||||||
|
|
||||||
_EOF
|
_EOF
|
||||||
|
|
Loading…
Reference in New Issue