Add Java bindings.
This commit is contained in:
parent
f774095496
commit
9fcf4d0b5b
|
@ -61,6 +61,13 @@ bindings/python/sigrok/core/lowlevel_wrap.c
|
|||
bindings/python/sigrok/core/classes.py
|
||||
bindings/python/sigrok/core/classes_wrap.cpp
|
||||
|
||||
# Files generated by building Java bindings
|
||||
*.class
|
||||
bindings/java/org/sigrok/core/classes/*.java
|
||||
bindings/java/org/sigrok/core/classes/classes_wrap.cxx
|
||||
bindings/java/libsigrok_java_core_classes.so
|
||||
bindings/java/sigrok-core.jar
|
||||
|
||||
# Files generated by the testsuite
|
||||
test-suite.log
|
||||
tests/*.log
|
||||
|
|
44
Makefile.am
44
Makefile.am
|
@ -427,6 +427,50 @@ CLEAN_EXTRA += python-clean
|
|||
|
||||
endif
|
||||
|
||||
if BINDINGS_JAVA
|
||||
|
||||
JDIR = bindings/java
|
||||
JPKG = org/sigrok/core/classes
|
||||
JINT = $(JDIR)/$(JPKG)/classes.i
|
||||
JSRC = $(JDIR)/$(JPKG)/classes_wrap.cxx
|
||||
JLIB = $(JDIR)/libsigrok_java_core_classes.so
|
||||
JJAR = $(JDIR)/sigrok-core.jar
|
||||
|
||||
java-build: $(JJAR) $(JLIB)
|
||||
|
||||
$(JSRC): $(JINT) bindings/swig/classes.i
|
||||
swig -c++ -java -package org.sigrok.core.classes \
|
||||
-Iinclude -Ibindings/cxx/include \
|
||||
-outdir $(JDIR)/$(JPKG) $(JINT)
|
||||
|
||||
$(JJAR): $(JSRC) $(JDIR)/$(JPKG)/*.java
|
||||
$(JAVAC) -sourcepath $(JDIR) $(JDIR)/$(JPKG)/*.java
|
||||
jar cf $(JJAR) -C $(JDIR) $(JPKG)
|
||||
|
||||
$(JLIB): $(JSRC) bindings/cxx/libsigrokxx.la
|
||||
$(CXX) $(CXXFLAGS) -L.libs -Lbindings/cxx/.libs \
|
||||
-fno-strict-aliasing -fPIC -shared \
|
||||
$(JDIR)/$(JPKG)/classes_wrap.cxx -lsigrokxx \
|
||||
-o $(JLIB)
|
||||
|
||||
java-install:
|
||||
$(INSTALL) -d $(libdir)/jni
|
||||
$(INSTALL) $(JLIB) -t $(libdir)/jni
|
||||
$(INSTALL) -d $(datadir)/java
|
||||
$(INSTALL) $(JJAR) -t $(datadir)/java
|
||||
|
||||
java-clean:
|
||||
rm $(JSRC)
|
||||
rm $(JDIR)/$(JPKG)/*.class
|
||||
rm $(JJAR)
|
||||
rm $(JLIB)
|
||||
|
||||
BUILD_EXTRA += java-build
|
||||
INSTALL_EXTRA += java-install
|
||||
CLEAN_EXTRA += java-clean
|
||||
|
||||
endif
|
||||
|
||||
all-local: $(BUILD_EXTRA)
|
||||
install-exec-local: $(INSTALL_EXTRA)
|
||||
clean-extra: $(CLEAN_EXTRA)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package org.sigrok.core.classes;
|
||||
|
||||
public interface DatafeedCallback
|
||||
{
|
||||
public void run(Device device, Packet packet);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.sigrok.core.classes;
|
||||
|
||||
public interface LogCallback
|
||||
{
|
||||
public void run(LogLevel loglevel, String message);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.sigrok.core.classes;
|
||||
|
||||
public interface SourceCallback
|
||||
{
|
||||
public void run(int revents);
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
%module classes
|
||||
|
||||
/* Automatically load JNI library. */
|
||||
%pragma(java) jniclasscode=%{
|
||||
static {
|
||||
System.loadLibrary("sigrok_java_core_classes");
|
||||
}
|
||||
%}
|
||||
|
||||
/* Map Java FileDescriptor objects to int fds */
|
||||
%typemap(jni) int fd "jobject"
|
||||
%typemap(jtype) int fd "java.io.FileDescriptor"
|
||||
%typemap(jstype) int fd "java.io.FileDescriptor"
|
||||
%typemap(javain) int fd "$javainput"
|
||||
|
||||
%typemap(in) int fd {
|
||||
jclass FileDescriptor = jenv->FindClass("java/io/FileDescriptor");
|
||||
jfieldID fd = jenv->GetFieldID(FileDescriptor, "fd", "I");
|
||||
$1 = jenv->GetIntField($input, fd);
|
||||
}
|
||||
|
||||
/* Map Glib::VariantBase to a Variant class in Java */
|
||||
%rename(Variant) VariantBase;
|
||||
namespace Glib {
|
||||
class VariantBase {};
|
||||
}
|
||||
|
||||
/* Map between std::vector and java.util.Vector */
|
||||
%define VECTOR(CValue, JValue)
|
||||
|
||||
%typemap(jni) std::vector< CValue > "jobject"
|
||||
%typemap(jtype) std::vector< CValue > "java.util.Vector<JValue>"
|
||||
%typemap(jstype) std::vector< CValue > "java.util.Vector<JValue>"
|
||||
|
||||
%typemap(javain,
|
||||
pre=" $javaclassname temp$javainput = $javaclassname.convertVector($javainput);",
|
||||
pgcppname="temp$javainput")
|
||||
std::vector< CValue > "$javaclassname.getCPtr(temp$javainput)"
|
||||
|
||||
%typemap(javacode) std::vector< CValue > %{
|
||||
static $javaclassname convertVector(java.util.Vector<JValue> in)
|
||||
{
|
||||
$javaclassname out = new $javaclassname();
|
||||
for (JValue value : in)
|
||||
out.add(value);
|
||||
return out;
|
||||
}
|
||||
%}
|
||||
|
||||
%typemap(javaout) std::vector< CValue > {
|
||||
return (java.util.Vector<JValue>)$jnicall;
|
||||
}
|
||||
|
||||
%typemap(out) std::vector< CValue > {
|
||||
jclass Vector = jenv->FindClass("java/util/Vector");
|
||||
jmethodID Vector_init = jenv->GetMethodID(Vector, "<init>", "()V");
|
||||
jmethodID Vector_add = jenv->GetMethodID(Vector, "add",
|
||||
"(Ljava/lang/Object;)Z");
|
||||
jclass Value = jenv->FindClass("org/sigrok/core/classes/" #JValue);
|
||||
jmethodID Value_init = jenv->GetMethodID(Value, "<init>", "(JZ)V");
|
||||
$result = jenv->NewObject(Vector, Vector_init);
|
||||
jlong value;
|
||||
for (auto entry : $1)
|
||||
{
|
||||
*(CValue **) &value = new CValue(entry);
|
||||
jenv->CallObjectMethod($result, Vector_add,
|
||||
jenv->NewObject(Value, Value_init, value, true));
|
||||
}
|
||||
}
|
||||
|
||||
%enddef
|
||||
|
||||
VECTOR(std::shared_ptr<sigrok::Channel>, Channel)
|
||||
VECTOR(std::shared_ptr<sigrok::HardwareDevice>, HardwareDevice)
|
||||
|
||||
/* Common macro for mapping between std::map and java.util.Map */
|
||||
|
||||
%define MAP_COMMON(CKey, CValue, JKey, JValue)
|
||||
|
||||
%typemap(jstype) std::map< CKey, CValue >
|
||||
"java.util.Map<JKey, JValue>"
|
||||
|
||||
%typemap(javain,
|
||||
pre=" $javaclassname temp$javainput = $javaclassname.convertMap($javainput);",
|
||||
pgcppname="temp$javainput")
|
||||
std::map< CKey, CValue > "$javaclassname.getCPtr(temp$javainput)"
|
||||
|
||||
%typemap(javacode) std::map< CKey, CValue > %{
|
||||
static $javaclassname convertMap(java.util.Map<JKey,JValue> in)
|
||||
{
|
||||
$javaclassname out = new $javaclassname();
|
||||
for (java.util.Map.Entry<JKey, JValue> entry : in.entrySet())
|
||||
out.set(entry.getKey(), entry.getValue());
|
||||
return out;
|
||||
}
|
||||
%}
|
||||
|
||||
%typemap(javaout) std::map< CKey, CValue > {
|
||||
return (java.util.Map<JKey, JValue>)$jnicall;
|
||||
}
|
||||
|
||||
%enddef
|
||||
|
||||
/* Specialisation for string->string maps. */
|
||||
|
||||
MAP_COMMON(std::string, std::string, String, String)
|
||||
|
||||
%typemap(out) std::map<std::string, std::string> {
|
||||
jclass HashMap = jenv->FindClass("java/util/HashMap");
|
||||
jmethodID init = jenv->GetMethodID(HashMap, "<init>", "()V");
|
||||
jmethodID put = jenv->GetMethodID(HashMap, "put",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
$result = jenv->NewObject(HashMap, init);
|
||||
for (auto entry : $1)
|
||||
jenv->CallObjectMethod($result, put,
|
||||
jenv->NewStringUTF(entry.first.c_str()),
|
||||
jenv->NewStringUTF(entry.second.c_str()));
|
||||
}
|
||||
|
||||
/* Specialisation macro for string->shared_ptr maps. */
|
||||
|
||||
%define STRING_TO_SHARED_PTR_MAP(ClassName)
|
||||
|
||||
%typemap(jni) std::map<std::string, std::shared_ptr<sigrok::ClassName> >
|
||||
"jobject"
|
||||
%typemap(jtype) std::map<std::string, std::shared_ptr<sigrok::ClassName> >
|
||||
"java.util.Map<String,ClassName>"
|
||||
|
||||
MAP_COMMON(std::string, std::shared_ptr<sigrok::ClassName>, String, ClassName)
|
||||
|
||||
%typemap(out) std::map<std::string, std::shared_ptr<sigrok::ClassName> > {
|
||||
jclass HashMap = jenv->FindClass("java/util/HashMap");
|
||||
jmethodID HashMap_init = jenv->GetMethodID(HashMap, "<init>", "()V");
|
||||
jmethodID HashMap_put = jenv->GetMethodID(HashMap, "put",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
jclass Value = jenv->FindClass("org/sigrok/core/classes/" #ClassName);
|
||||
jmethodID Value_init = jenv->GetMethodID(Value, "<init>", "(JZ)V");
|
||||
$result = jenv->NewObject(HashMap, HashMap_init);
|
||||
jlong value;
|
||||
for (auto entry : $1)
|
||||
{
|
||||
*(std::shared_ptr< sigrok::ClassName > **)&value =
|
||||
new std::shared_ptr< sigrok::ClassName>(entry.second);
|
||||
jenv->CallObjectMethod($result, HashMap_put,
|
||||
jenv->NewStringUTF(entry.first.c_str()),
|
||||
jenv->NewObject(Value, Value_init, value, true));
|
||||
}
|
||||
}
|
||||
|
||||
%enddef
|
||||
|
||||
STRING_TO_SHARED_PTR_MAP(Driver)
|
||||
STRING_TO_SHARED_PTR_MAP(InputFormat)
|
||||
STRING_TO_SHARED_PTR_MAP(OutputFormat)
|
||||
|
||||
/* Specialisation for ConfigKey->Variant maps */
|
||||
|
||||
MAP_COMMON(const sigrok::ConfigKey *, Glib::VariantBase, ConfigKey, Variant)
|
||||
|
||||
%typemap(out) std::map<const sigrok::ConfigKey *, Glib::VariantBase> {
|
||||
jclass HashMap = jenv->FindClass("java/util/HashMap");
|
||||
jmethodID HashMap_init = jenv->GetMethodID(HashMap, "<init>", "()V");
|
||||
jmethodID HashMap_put = jenv->GetMethodID(HashMap, "put",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
jclass ConfigKey = jenv->FindClass("org/sigrok/core/classes/ConfigKey");
|
||||
jmethodID ConfigKey_init = jenv->GetMethodID(ConfigKey, "<init>", "(JZ)V");
|
||||
jclass Variant = jenv->FindClass("org/sigrok/core/classes/Variant");
|
||||
jmethodID Variant_init = jenv->GetMethodID(Variant, "<init>", "(JZ)V");
|
||||
$result = jenv->NewObject(HashMap, HashMap_init);
|
||||
jlong key;
|
||||
jlong value;
|
||||
for (auto entry : $1)
|
||||
{
|
||||
*(const sigrok::ConfigKey **) &key = entry.first;
|
||||
*(Glib::VariantBase **) &value = new Glib::VariantBase(entry.second);
|
||||
jenv->CallObjectMethod($result, HashMap_put,
|
||||
jenv->NewObject(ConfigKey, ConfigKey_init, key, false));
|
||||
jenv->NewObject(Variant, Variant_init, value, true));
|
||||
}
|
||||
}
|
||||
|
||||
/* Support Driver.scan() with no arguments. */
|
||||
%extend sigrok::Driver {
|
||||
std::vector<std::shared_ptr<sigrok::HardwareDevice> > scan()
|
||||
{
|
||||
std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
|
||||
return $self->scan(options);
|
||||
}
|
||||
}
|
||||
|
||||
/* Support OutputFormat.create_output(device) with no options. */
|
||||
%extend sigrok::OutputFormat {
|
||||
std::shared_ptr<sigrok::Output> create_output(
|
||||
std::shared_ptr<sigrok::Device> device)
|
||||
{
|
||||
std::map<std::string, std::string> options;
|
||||
return $self->create_output(device, options);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass JNIEnv parameter to C++ extension methods requiring it. */
|
||||
|
||||
%typemap(in, numinputs=0) JNIEnv * %{
|
||||
$1 = jenv;
|
||||
%}
|
||||
|
||||
/* Support Java log callbacks. */
|
||||
|
||||
%inline {
|
||||
typedef jobject jlogcallback;
|
||||
}
|
||||
|
||||
%typemap(jni) jlogcallback "jlogcallback"
|
||||
%typemap(jtype) jlogcallback "LogCallback"
|
||||
%typemap(jstype) jlogcallback "LogCallback"
|
||||
%typemap(javain) jlogcallback "$javainput"
|
||||
|
||||
%extend sigrok::Context
|
||||
{
|
||||
void add_log_callback(JNIEnv *env, jlogcallback obj)
|
||||
{
|
||||
jclass obj_class = env->GetObjectClass(obj);
|
||||
jmethodID method = env->GetMethodID(obj_class, "run",
|
||||
"(Lorg/sigrok/core/classes/LogLevel;Ljava/lang/String;)V");
|
||||
jclass LogLevel = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/sigrok/core/classes/LogLevel"));
|
||||
jmethodID LogLevel_init = env->GetMethodID(LogLevel, "<init>", "(JZ)V");
|
||||
jobject obj_ref = env->NewGlobalRef(obj);
|
||||
|
||||
$self->set_log_callback([=] (
|
||||
const sigrok::LogLevel *loglevel,
|
||||
std::string message)
|
||||
{
|
||||
jlong loglevel_addr;
|
||||
*(const sigrok::LogLevel **) &loglevel_addr = loglevel;
|
||||
jobject loglevel_obj = env->NewObject(
|
||||
LogLevel, LogLevel_init, loglevel_addr, false);
|
||||
jobject message_obj = env->NewStringUTF(message.c_str());
|
||||
env->CallVoidMethod(obj_ref, method, loglevel_obj, message_obj);
|
||||
if (env->ExceptionCheck())
|
||||
throw sigrok::Error(SR_ERR);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Support Java datafeed callbacks. */
|
||||
|
||||
%inline {
|
||||
typedef jobject jdatafeedcallback;
|
||||
}
|
||||
|
||||
%typemap(jni) jdatafeedcallback "jdatafeedcallback"
|
||||
%typemap(jtype) jdatafeedcallback "DatafeedCallback"
|
||||
%typemap(jstype) jdatafeedcallback "DatafeedCallback"
|
||||
%typemap(javain) jdatafeedcallback "$javainput"
|
||||
|
||||
%extend sigrok::Session
|
||||
{
|
||||
void add_datafeed_callback(JNIEnv *env, jdatafeedcallback obj)
|
||||
{
|
||||
jclass obj_class = env->GetObjectClass(obj);
|
||||
jmethodID method = env->GetMethodID(obj_class, "run",
|
||||
"(Lorg/sigrok/core/classes/Device;Lorg/sigrok/core/classes/Packet;)V");
|
||||
jclass Device = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/sigrok/core/classes/Device"));
|
||||
jmethodID Device_init = env->GetMethodID(Device, "<init>", "(JZ)V");
|
||||
jclass Packet = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/sigrok/core/classes/Packet"));
|
||||
jmethodID Packet_init = env->GetMethodID(Packet, "<init>", "(JZ)V");
|
||||
jobject obj_ref = env->NewGlobalRef(obj);
|
||||
|
||||
$self->add_datafeed_callback([=] (
|
||||
std::shared_ptr<sigrok::Device> device,
|
||||
std::shared_ptr<sigrok::Packet> packet)
|
||||
{
|
||||
jlong device_addr;
|
||||
jlong packet_addr;
|
||||
*(std::shared_ptr<sigrok::Device> **) &device_addr =
|
||||
new std::shared_ptr<sigrok::Device>(device);
|
||||
*(std::shared_ptr<sigrok::Packet> **) &packet_addr =
|
||||
new std::shared_ptr<sigrok::Packet>(packet);
|
||||
jobject device_obj = env->NewObject(
|
||||
Device, Device_init, device_addr, true);
|
||||
jobject packet_obj = env->NewObject(
|
||||
Packet, Packet_init, packet_addr, true);
|
||||
env->CallVoidMethod(obj_ref, method, device_obj, packet_obj);
|
||||
if (env->ExceptionCheck())
|
||||
throw sigrok::Error(SR_ERR);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Support Java event source callbacks. */
|
||||
|
||||
%inline {
|
||||
typedef jobject jsourcecallback;
|
||||
}
|
||||
|
||||
%typemap(jni) jsourcecallback "jsourcecallback"
|
||||
%typemap(jtype) jsourcecallback "SourceCallback"
|
||||
%typemap(jstype) jsourcecallback "SourceCallback"
|
||||
%typemap(javain) jsourcecallback "$javainput"
|
||||
|
||||
%extend sigrok::EventSource
|
||||
{
|
||||
std::shared_ptr<sigrok::EventSource> create(
|
||||
int fd, Glib::IOCondition events, int timeout,
|
||||
JNIEnv *env, jsourcecallback obj)
|
||||
{
|
||||
(void) $self;
|
||||
jclass obj_class = env->GetObjectClass(obj);
|
||||
jmethodID method = env->GetMethodID(obj_class, "run", "(I)V");
|
||||
jobject obj_ref = env->NewGlobalRef(obj);
|
||||
|
||||
return sigrok::EventSource::create(fd, events, timeout, [=] (int revents)
|
||||
{
|
||||
bool result = env->CallBooleanMethod(obj_ref, method, revents);
|
||||
if (env->ExceptionCheck())
|
||||
throw sigrok::Error(SR_ERR);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
%include "bindings/swig/classes.i"
|
25
configure.ac
25
configure.ac
|
@ -166,6 +166,11 @@ AC_ARG_ENABLE(python,
|
|||
[build Python bindings [default=yes]]),
|
||||
[BINDINGS_PYTHON="$enableval"], [BINDINGS_PYTHON="yes"])
|
||||
|
||||
AC_ARG_ENABLE(java,
|
||||
AC_HELP_STRING([--enable-java],
|
||||
[build Java bindings [default=yes]]),
|
||||
[BINDINGS_PYTHON="$enableval"], [BINDINGS_JAVA="yes"])
|
||||
|
||||
# Check if the C++ compiler supports the C++11 standard.
|
||||
|
||||
AX_CXX_COMPILE_STDCXX_11(,[optional])
|
||||
|
@ -174,10 +179,11 @@ if test "x$HAVE_CXX11" != "x1"; then
|
|||
BINDINGS_CXX="no"
|
||||
fi
|
||||
|
||||
# Python bindings depend on C++ bindings.
|
||||
# Python and Java bindings depend on C++ bindings.
|
||||
|
||||
if test "x$BINDINGS_CXX" != "xyes"; then
|
||||
BINDINGS_PYTHON="no"
|
||||
BINDINGS_JAVA="no"
|
||||
fi
|
||||
|
||||
# Checks for libraries.
|
||||
|
@ -362,6 +368,20 @@ AC_SUBST(SR_PKGLIBS)
|
|||
CFLAGS="$CFLAGS -I./include/libsigrok $LIB_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -I./include -I./bindings/cxx/include $LIB_CFLAGS"
|
||||
|
||||
# Find Java compiler and JNI includes for Java bindings.
|
||||
|
||||
AC_CHECK_PROG([HAVE_JAVAC], [javac], [yes], [no])
|
||||
|
||||
if test "x$HAVE_JAVAC" = "xyes"; then
|
||||
AX_PROG_JAVAC
|
||||
AX_JNI_INCLUDE_DIR
|
||||
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
|
||||
CXXFLAGS="$CXXFLAGS -I$JNI_INCLUDE_DIR"
|
||||
done
|
||||
else
|
||||
BINDINGS_JAVA="no"
|
||||
fi
|
||||
|
||||
# Now set AM_CONDITIONALs and AC_DEFINEs for the enabled/disabled drivers.
|
||||
|
||||
AM_CONDITIONAL(HW_AGILENT_DMM, test x$HW_AGILENT_DMM = xyes)
|
||||
|
@ -553,6 +573,8 @@ AM_CONDITIONAL(BINDINGS_CXX, test x$BINDINGS_CXX = xyes)
|
|||
|
||||
AM_CONDITIONAL(BINDINGS_PYTHON, test x$BINDINGS_PYTHON = xyes)
|
||||
|
||||
AM_CONDITIONAL(BINDINGS_JAVA, test x$BINDINGS_JAVA = xyes)
|
||||
|
||||
# Checks for header files.
|
||||
# These are already checked: inttypes.h stdint.h stdlib.h string.h unistd.h.
|
||||
|
||||
|
@ -609,4 +631,5 @@ echo -e "\nEnabled hardware drivers:\n${driver_summary}"
|
|||
echo -e "\nEnabled language bindings:\n"
|
||||
echo " - C++............................. $BINDINGS_CXX"
|
||||
echo " - Python.......................... $BINDINGS_PYTHON"
|
||||
echo " - Java............................ $BINDINGS_JAVA"
|
||||
echo
|
||||
|
|
Loading…
Reference in New Issue