From c63e38a57e4588904278b9b9c0b3c22140c30dff Mon Sep 17 00:00:00 2001 From: Petre Eftime Date: Wed, 16 Dec 2015 16:56:38 +0200 Subject: [PATCH] java: Migrate IsrCallbacks to Java's Runnable class Signed-off-by: Petre Eftime Signed-off-by: Brendan Le Foll --- api/mraa/gpio.h | 6 ++++ api/mraa/gpio.hpp | 34 ++++------------------ examples/java/Isr.java | 7 ++--- src/CMakeLists.txt | 1 + src/gpio/gpio.c | 63 +++++++++++++++++++++++++++++++++++++++++ src/java/CMakeLists.txt | 7 ++++- src/java/mraajava.i | 11 +++++-- src/mraa.i | 1 + src/mraajava.pc.cmake | 11 +++++++ 9 files changed, 104 insertions(+), 37 deletions(-) create mode 100644 src/mraajava.pc.cmake diff --git a/api/mraa/gpio.h b/api/mraa/gpio.h index 895d537..2168f50 100644 --- a/api/mraa/gpio.h +++ b/api/mraa/gpio.h @@ -44,6 +44,12 @@ extern "C" { #include #endif +#if defined(SWIGJAVA) || defined(JAVACALLBACK) +#include +extern JavaVM *globVM; +extern void mraa_java_isr_callback(void *); +#endif + #include #include diff --git a/api/mraa/gpio.hpp b/api/mraa/gpio.hpp index b578463..ec9c43a 100644 --- a/api/mraa/gpio.hpp +++ b/api/mraa/gpio.hpp @@ -69,30 +69,6 @@ typedef enum { EDGE_FALLING = 3 /**< Interupt on falling only */ } Edge; -#if defined(SWIGJAVA) - -class IsrCallback -{ - friend class Gpio; - public: - virtual ~IsrCallback() - { - } - virtual void - run() - { /* empty, overloaded in Java*/ - } - - protected: - static void - generic_isr_callback(void* data) - { - IsrCallback* callback = (IsrCallback*) data; - callback->run(); - } -}; -#endif - /** * @brief API to General Purpose IO * @@ -196,13 +172,13 @@ class Gpio #endif return (Result) mraa_gpio_isr(m_gpio, (mraa_gpio_edge_t) mode, &uvwork, this); } -#elif defined(SWIGJAVA) +#elif defined(SWIGJAVA) || defined(JAVACALLBACK) Result - isr(Edge mode, IsrCallback* cb) + isr(Edge mode, jobject runnable) { - return (Result) mraa_gpio_isr(m_gpio, (mraa_gpio_edge_t) mode, &IsrCallback::generic_isr_callback, cb); + return (Result) mraa_gpio_isr(m_gpio, (mraa_gpio_edge_t) mode, mraa_java_isr_callback, runnable); } -#else +#endif /** * Sets a callback to be called when pin value changes * @@ -217,7 +193,7 @@ class Gpio { return (Result) mraa_gpio_isr(m_gpio, (mraa_gpio_edge_t) mode, fptr, args); } -#endif + /** * Exits callback - this call will not kill the isr thread immediatly * but only when it is out of it's critical section diff --git a/examples/java/Isr.java b/examples/java/Isr.java index 6881bf5..72a1d3e 100644 --- a/examples/java/Isr.java +++ b/examples/java/Isr.java @@ -25,7 +25,6 @@ import mraa.Dir; import mraa.Edge; import mraa.Gpio; -import mraa.IsrCallback; public class Isr { static { @@ -41,7 +40,7 @@ public class Isr { public static void main(String argv[]) throws InterruptedException { Gpio gpio = new Gpio(6); - IsrCallback callback = new JavaCallback(); + Runnable callback = new JavaCallback(); gpio.isr(Edge.EDGE_RISING, callback); while (true) @@ -49,8 +48,6 @@ public class Isr { }; } -class JavaCallback extends IsrCallback { - public JavaCallback() { super(); } - +class JavaCallback extends Runnable { public void run() { System.out.println("JavaCallback.run()"); } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 05b546c..199c045 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -130,6 +130,7 @@ macro (mraa_CREATE_INSTALL_PKGCONFIG generated_file install_location) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} DESTINATION ${install_location}) endmacro (mraa_CREATE_INSTALL_PKGCONFIG) mraa_create_install_pkgconfig (mraa.pc ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +mraa_create_install_pkgconfig (mraajava.pc ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS mraa DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index 411a02a..b1a757c 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -234,6 +234,36 @@ mraa_gpio_wait_interrupt(int fd return MRAA_SUCCESS; } +#if defined(SWIGJAVA) || defined(JAVACALLBACK) +pthread_key_t env_key; + +extern JavaVM *globVM; +static pthread_once_t env_key_init = PTHREAD_ONCE_INIT; + +jmethodID runGlobal; + +static void make_env_key(void) +{ + + JNIEnv *jenv; + (*globVM)->GetEnv(globVM, (void **)&jenv, JNI_VERSION_1_8); + + jclass rcls = (*jenv)->FindClass(jenv, "java/lang/Runnable"); + jmethodID runm = (*jenv)->GetMethodID(jenv, rcls, "run", "()V"); + + runGlobal = (jmethodID)(*jenv)->NewGlobalRef(jenv, (jobject)runm); + + pthread_key_create(&env_key, NULL); +} + +void mraa_java_isr_callback(void* data) +{ + JNIEnv *jenv = (JNIEnv *) pthread_getspecific(env_key); + (*jenv)->CallVoidMethod(jenv, (jobject)data, runGlobal); +} + +#endif + static void* mraa_gpio_interrupt_handler(void* arg) { @@ -262,6 +292,22 @@ mraa_gpio_interrupt_handler(void* arg) dev->isr_value_fp = fp; +#if defined(SWIGJAVA) || defined(JAVACALLBACK) + JNIEnv *jenv; + if(dev->isr == mraa_java_isr_callback) { + jint err = (*globVM)->AttachCurrentThreadAsDaemon(globVM, (void **)&jenv, NULL); + + if (err != JNI_OK) { + close(dev->isr_value_fp); + dev->isr_value_fp = -1; + return NULL; + } + + pthread_once(&env_key_init, make_env_key); + pthread_setspecific(env_key, jenv); + } +#endif + for (;;) { ret = mraa_gpio_wait_interrupt(dev->isr_value_fp #ifndef HAVE_PTHREAD_CANCEL @@ -347,6 +393,13 @@ mraa_gpio_interrupt_handler(void* arg) #endif close(dev->isr_value_fp); dev->isr_value_fp = -1; +#if defined(SWIGJAVA) || defined(JAVACALLBACK) + + if(dev->isr == mraa_java_isr_callback) { + (*jenv)->DeleteGlobalRef(jenv, (jobject)dev->isr_args); + (*globVM)->DetachCurrentThread(globVM); + } +#endif return NULL; } } @@ -414,6 +467,16 @@ mraa_gpio_isr(mraa_gpio_context dev, mraa_gpio_edge_t mode, void (*fptr)(void*), } dev->isr = fptr; +#if defined(SWIGJAVA) || defined(JAVACALLBACK) + JNIEnv *jenv; + /* Most UPM sensors use the C API, the global ref must be created here. */ + /* The reason for checking the callback function is internal callbacks. */ + if (fptr == mraa_java_isr_callback) { + (*globVM)->GetEnv(globVM, (void **)&jenv, JNI_VERSION_1_8); + jobject grunnable = (*jenv)->NewGlobalRef(jenv, (jobject) args); + args = (void *) grunnable; + } +#endif dev->isr_args = args; pthread_create(&dev->thread_id, NULL, mraa_gpio_interrupt_handler, (void*) dev); diff --git a/src/java/CMakeLists.txt b/src/java/CMakeLists.txt index 5225d3b..c8b0056 100644 --- a/src/java/CMakeLists.txt +++ b/src/java/CMakeLists.txt @@ -10,7 +10,8 @@ include_directories ( set_source_files_properties (mraajava.i PROPERTIES SWIG_FLAGS ";-package;mraa;-I${CMAKE_BINARY_DIR}/src") set_source_files_properties (mraajava.i PROPERTIES CPLUSPLUS ON) -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -DJAVACALLBACK") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DJAVACALLBACK") if (NOT DEFINED $ENV{JAVA_HOME_NATIVE}) set (JAVA_HOME_NATIVE $ENV{JAVA_HOME}) @@ -29,6 +30,7 @@ add_custom_command (TARGET mraajava COMMAND cmake -E echo "Compiling java.." COMMAND cmake -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/mraa COMMAND ${JAVAC} *.java -d ${CMAKE_CURRENT_BINARY_DIR} + COMMAND cmake -E create_symlink java/libmraajava.so ${CMAKE_CURRENT_BINARY_DIR}/../libmraajava.so COMMAND cmake -E echo "Creating jar" COMMAND ${JAR} cvf mraa.jar mraa ) @@ -42,6 +44,9 @@ endif () install (FILES ${CMAKE_CURRENT_BINARY_DIR}/libmraajava.so DESTINATION lib/java ) +install (FILES ${CMAKE_CURRENT_BINARY_DIR}/../libmraajava.so + DESTINATION lib/ +) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/mraa.jar DESTINATION lib/java ) diff --git a/src/java/mraajava.i b/src/java/mraajava.i index 997b772..d8b698b 100644 --- a/src/java/mraajava.i +++ b/src/java/mraajava.i @@ -42,6 +42,9 @@ return $jnicall; } +%typemap(jtype) jobject runnable "java.lang.Runnable" +%typemap(jstype) jobject runnable "java.lang.Runnable" + namespace mraa { class Spi; %typemap(out) uint8_t* @@ -55,14 +58,18 @@ class Spi; %ignore write(const char* data, int length); %ignore read(char* data, int length); +%ignore globVM; +%ignore env_key; +%ignore mraa_java_isr_callback; -%feature("director") IsrCallback; -SWIG_DIRECTOR_OWNED(IsrCallback) %include ../mraa.i %wrapper %{ + JavaVM *globVM; + jint JNI_OnLoad(JavaVM *vm, void *reserved) { /* initialize mraa */ + globVM = vm; mraa_init(); return JNI_VERSION_1_8; } diff --git a/src/mraa.i b/src/mraa.i index 2aea6ba..7a2d03e 100644 --- a/src/mraa.i +++ b/src/mraa.i @@ -46,6 +46,7 @@ %ignore Gpio::v8isr(uv_work_t* req); %ignore Gpio::v8isr(uv_work_t* req, int status); %ignore Gpio::uvwork(void *ctx); +%ignore Gpio::isr(Edge mode, void (*fptr)(void*), void* args); %include "gpio.hpp" diff --git a/src/mraajava.pc.cmake b/src/mraajava.pc.cmake new file mode 100644 index 0000000..e234153 --- /dev/null +++ b/src/mraajava.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib@LIB_SUFFIX@ +includedir=${prefix}/include + +Name: mraa +Description: Low Level Skeleton Library for Communication +Version: @mraa_VERSION_STRING@ + +Libs: -L${libdir} -lmraajava +Cflags: -I${includedir}