X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=bindings%2Fjava%2Forg%2Fsigrok%2Fcore%2Fclasses%2Fclasses.i;h=e953fe5d8331052215b59e5c97608c50e851da8a;hb=e803574173bdac8a7f33085a648c29eaf248a394;hp=44efc1c51e43f396c327e84b2710af2f292e3f5d;hpb=5faebab2903dc91949edc31f0a4b118d86090a30;p=libsigrok.git diff --git a/bindings/java/org/sigrok/core/classes/classes.i b/bindings/java/org/sigrok/core/classes/classes.i index 44efc1c5..e953fe5d 100644 --- a/bindings/java/org/sigrok/core/classes/classes.i +++ b/bindings/java/org/sigrok/core/classes/classes.i @@ -11,25 +11,25 @@ %pragma(java) jniclassimports=%{ /** * @mainpage API Reference - * + * * Introduction * ------------ - * + * * The sigrok-java API provides an object-oriented Java interface to the * functionality in libsigrok. It is built on top of the libsigrokcxx C++ API. - * + * * Getting started * --------------- - * + * * Usage of the sigrok-java 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. */ @@ -44,6 +44,8 @@ namespace Glib { class VariantBase {}; } +%include "bindings/swig/templates.i" + /* Map between std::vector and java.util.Vector */ %define VECTOR(CValue, JValue) @@ -52,20 +54,12 @@ namespace Glib { %typemap(jstype) std::vector< CValue > "java.util.Vector" %typemap(javain, - pre=" $javaclassname temp$javainput = $javaclassname.convertVector($javainput);", + pre=" $javaclassname temp$javainput = new $javaclassname(); + for (JValue value : $javainput) + temp$javainput.add(value);", pgcppname="temp$javainput") std::vector< CValue > "$javaclassname.getCPtr(temp$javainput)" -%typemap(javacode) std::vector< CValue > %{ - static $javaclassname convertVector(java.util.Vector in) - { - $javaclassname out = new $javaclassname(); - for (JValue value : in) - out.add(value); - return out; - } -%} - %typemap(javaout) std::vector< CValue > { return (java.util.Vector)$jnicall; } @@ -78,11 +72,11 @@ namespace Glib { jclass Value = jenv->FindClass("org/sigrok/core/classes/" #JValue); jmethodID Value_init = jenv->GetMethodID(Value, "", "(JZ)V"); $result = jenv->NewObject(Vector, Vector_init); - jlong value; + jlong value = 0; for (auto entry : $1) { *(CValue **) &value = new CValue(entry); - jenv->CallObjectMethod($result, Vector_add, + jenv->CallBooleanMethod($result, Vector_add, jenv->NewObject(Value, Value_init, value, true)); } } @@ -100,20 +94,20 @@ VECTOR(std::shared_ptr, HardwareDevice) "java.util.Map" %typemap(javain, - pre=" $javaclassname temp$javainput = $javaclassname.convertMap($javainput);", +/* SWIG 4.0.0 changed the std::map wrappers in an incompatible way. */ +#if SWIG_VERSION >= 0x040000 + pre=" $javaclassname temp$javainput = new $javaclassname(); + for (java.util.Map.Entry entry : $javainput.entrySet()) + temp$javainput.put(entry.getKey(), entry.getValue());", + pgcppname="temp$javainput") +#else + pre=" $javaclassname temp$javainput = new $javaclassname(); + for (java.util.Map.Entry entry : $javainput.entrySet()) + temp$javainput.set(entry.getKey(), entry.getValue());", pgcppname="temp$javainput") +#endif std::map< CKey, CValue > "$javaclassname.getCPtr(temp$javainput)" -%typemap(javacode) std::map< CKey, CValue > %{ - static $javaclassname convertMap(java.util.Map in) - { - $javaclassname out = new $javaclassname(); - for (java.util.Map.Entry entry : in.entrySet()) - out.set(entry.getKey(), entry.getValue()); - return out; - } -%} - %typemap(javaout) std::map< CKey, CValue > { return (java.util.Map)$jnicall; } @@ -160,7 +154,7 @@ MAP_COMMON(std::string, std::shared_ptr, String, ClassName) jclass Value = jenv->FindClass("org/sigrok/core/classes/" #ClassName); jmethodID Value_init = jenv->GetMethodID(Value, "", "(JZ)V"); $result = jenv->NewObject(HashMap, HashMap_init); - jlong value; + jlong value = 0; for (auto entry : $1) { *(std::shared_ptr< sigrok::ClassName > **)&value = @@ -195,8 +189,8 @@ MAP_COMMON(const sigrok::ConfigKey *, Glib::VariantBase, ConfigKey, Variant) jclass Variant = jenv->FindClass("org/sigrok/core/classes/Variant"); jmethodID Variant_init = jenv->GetMethodID(Variant, "", "(JZ)V"); $result = jenv->NewObject(HashMap, HashMap_init); - jlong key; - jlong value; + jlong key = 0; + jlong value = 0; for (auto entry : $1) { *(const sigrok::ConfigKey **) &key = entry.first; @@ -207,77 +201,77 @@ MAP_COMMON(const sigrok::ConfigKey *, Glib::VariantBase, ConfigKey, Variant) } } -/* Support Driver.scan() with no arguments. */ -%ignore sigrok::Driver::scan; - -%extend sigrok::Driver { - std::vector > scan() - { - std::map options; - return $self->scan(options); - } +/* Pass JNIEnv parameter to C++ extension methods requiring it. */ - std::vector > scan( - std::map options) - { - return $self->scan(options); - } -} +%typemap(in, numinputs=0) JNIEnv * %{ + $1 = jenv; +%} -/* Support InputFormat.create_input() with or without options. */ -%ignore sigrok::InputFormat::create_input; +/* Thread safe JNIEnv handling */ -%extend sigrok::InputFormat { - std::shared_ptr create_input() - { - return $self->create_input(); +%inline { +namespace { + class ScopedEnv { + public: + ScopedEnv(JavaVM *jvm); + ~ScopedEnv(); + JNIEnv* operator-> () { return env; } + operator bool () const { return (bool)env; } + private: + JavaVM *jvm; + JNIEnv *env; + int env_status; + }; + ScopedEnv::ScopedEnv(JavaVM *jvm) : jvm(jvm), env(NULL) { + env_status = jvm->GetEnv((void **)&env, JNI_VERSION_1_2); + if (env_status == JNI_EDETACHED) { +%#if defined(__ANDROID__) + jvm->AttachCurrentThread(&env, NULL); +%#else + jvm->AttachCurrentThread((void **)&env, NULL); +%#endif + } } - - std::shared_ptr create_input( - std::map options) - { - return $self->create_input(options); + ScopedEnv::~ScopedEnv() { + if (env_status == JNI_EDETACHED) { + jvm->DetachCurrentThread(); + } } } +} -/* Support OutputFormat.create_output() with or without options. */ -%ignore sigrok::OutputFormat::create_output; +/* "Smartpointer" for Java references. */ -%extend sigrok::OutputFormat { - std::shared_ptr create_output( - std::shared_ptr device) +%inline { +namespace { + class GlobalRefBase { - return $self->create_output(device); + protected: + GlobalRefBase (JavaVM *jvm, jobject ref); + ~GlobalRefBase (); + JavaVM *jvm; + jobject jref; + }; + GlobalRefBase::GlobalRefBase (JavaVM *jvm, jobject ref) : jvm(jvm), jref(0) { + ScopedEnv env(jvm); + if (env && ref) + jref = env->NewGlobalRef(ref); } - - std::shared_ptr create_output( - std::shared_ptr device, - std::map options) - { - return $self->create_output(device, options); + GlobalRefBase::~GlobalRefBase () { + ScopedEnv env(jvm); + if(env && jref) + env->DeleteGlobalRef(jref); } - - std::shared_ptr create_output( - std::string filename, - std::shared_ptr device) + template + class GlobalRef : private GlobalRefBase { - return $self->create_output(filename, device); - } - - std::shared_ptr create_output( - std::string filename, - std::shared_ptr device, - std::map options) - { - return $self->create_output(filename, device, options); - } + public: + GlobalRef (JavaVM *jvm, Jtype ref) : GlobalRefBase(jvm, ref) {} + GlobalRef (const GlobalRef &ref) : GlobalRefBase(ref.jvm, ref.jref) {} + operator Jtype () const { return static_cast(jref); } + }; +} } - -/* Pass JNIEnv parameter to C++ extension methods requiring it. */ - -%typemap(in, numinputs=0) JNIEnv * %{ - $1 = jenv; -%} /* Support Java log callbacks. */ @@ -297,19 +291,23 @@ typedef jobject jlogcallback; { void add_log_callback(JNIEnv *env, jlogcallback obj) { + JavaVM *jvm = NULL; + env->GetJavaVM(&jvm); 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")); + GlobalRef LogLevel(jvm, env->FindClass("org/sigrok/core/classes/LogLevel")); jmethodID LogLevel_init = env->GetMethodID(LogLevel, "", "(JZ)V"); - jobject obj_ref = env->NewGlobalRef(obj); + GlobalRef obj_ref(jvm, obj); $self->set_log_callback([=] ( const sigrok::LogLevel *loglevel, std::string message) { - jlong loglevel_addr; + ScopedEnv env(jvm); + if (!env) + throw sigrok::Error(SR_ERR); + jlong loglevel_addr = 0; *(const sigrok::LogLevel **) &loglevel_addr = loglevel; jobject loglevel_obj = env->NewObject( LogLevel, LogLevel_init, loglevel_addr, false); @@ -339,23 +337,26 @@ typedef jobject jdatafeedcallback; { void add_datafeed_callback(JNIEnv *env, jdatafeedcallback obj) { + JavaVM *jvm = NULL; + env->GetJavaVM(&jvm); 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")); + GlobalRef Device(jvm, env->FindClass("org/sigrok/core/classes/Device")); jmethodID Device_init = env->GetMethodID(Device, "", "(JZ)V"); - jclass Packet = (jclass) env->NewGlobalRef( - env->FindClass("org/sigrok/core/classes/Packet")); + GlobalRef Packet(jvm, env->FindClass("org/sigrok/core/classes/Packet")); jmethodID Packet_init = env->GetMethodID(Packet, "", "(JZ)V"); - jobject obj_ref = env->NewGlobalRef(obj); + GlobalRef obj_ref(jvm, obj); $self->add_datafeed_callback([=] ( std::shared_ptr device, std::shared_ptr packet) { - jlong device_addr; - jlong packet_addr; + ScopedEnv env(jvm); + if (!env) + throw sigrok::Error(SR_ERR); + jlong device_addr = 0; + jlong packet_addr = 0; *(std::shared_ptr **) &device_addr = new std::shared_ptr(device); *(std::shared_ptr **) &packet_addr = @@ -373,19 +374,13 @@ typedef jobject jdatafeedcallback; %include "doc.i" -%define %attributevector(Class, Type, Name, Get) -%attributeval(sigrok::Class, Type, Name, Get); -%enddef - -%define %attributemap(Class, Type, Name, Get) -%attributeval(sigrok::Class, Type, Name, Get); -%enddef - %define %enumextras(Class) %enddef -/* Ignore this for now, needs a fix. */ -%ignore sigrok::Context::create_analog_old_packet; +/* Ignore these for now, need fixes. */ +%ignore sigrok::Context::create_analog_packet; +%ignore sigrok::Context::create_meta_packet; +%ignore sigrok::Meta::config; %include "bindings/swig/classes.i"