diff --git a/src/java/mraajni.c b/src/java/mraajni.c index e5c6e6f..306756f 100644 --- a/src/java/mraajni.c +++ b/src/java/mraajni.c @@ -29,7 +29,7 @@ static pthread_key_t env_key; static pthread_once_t env_key_init = PTHREAD_ONCE_INIT; static jmethodID runGlobal; static JavaVM* globVM = NULL; - +static jclass jcObject; void mraa_java_set_jvm(JavaVM* vm) @@ -44,8 +44,24 @@ mraa_java_make_env_key(void) JNIEnv* jenv; (*globVM)->GetEnv(globVM, (void**) &jenv, JNI_REQUIRED_VERSION); jclass rcls = (*jenv)->FindClass(jenv, "java/lang/Runnable"); - jmethodID runm = (*jenv)->GetMethodID(jenv, rcls, "run", "()V"); - runGlobal = (jmethodID)(*jenv)->NewGlobalRef(jenv, (jobject) runm); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionClear(jenv); + return; + } + + jcObject = (jclass) (*jenv)->NewGlobalRef(jenv, rcls); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionClear(jenv); + return; + } + (*jenv)->DeleteLocalRef(jenv, rcls); + + runGlobal = (*jenv)->GetMethodID(jenv, jcObject, "run", "()V"); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionClear(jenv); + return; + } + pthread_key_create(&env_key, NULL); } } diff --git a/src/peripheralman/peripheralman.c b/src/peripheralman/peripheralman.c index 9a0660a..30cbadf 100644 --- a/src/peripheralman/peripheralman.c +++ b/src/peripheralman/peripheralman.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "mraa_internal.h" #include "peripheralmanager/peripheralman.h" @@ -721,10 +723,111 @@ mraa_pman_gpio_edge_mode_replace(mraa_gpio_context dev, mraa_gpio_edge_t mode) return MRAA_SUCCESS; }; +static mraa_result_t +mraa_pman_gpio_wait_interrupt(int fd, int control_fd) +{ + if (fd < 0) { + return MRAA_ERROR_INVALID_PARAMETER; + } + + struct pollfd poller = { + .fd = fd, + .events = POLLIN | POLLPRI | POLLERR, + .revents = 0, + }; + + poll(&poller, 1, -1); + syslog(LOG_INFO, "peripheralman: received an event"); + AGpio_ackInterruptEvent(fd); + + return MRAA_SUCCESS; +} + +static void* +mraa_pman_gpio_interrupt_handler(void* arg) +{ + if (arg == NULL) { + syslog(LOG_ERR, "peripheralman: interrupt_handler: context is invalid"); + return NULL; + } + + mraa_gpio_context dev = (mraa_gpio_context) arg; + int fd = -1; + + if (AGpio_getPollingFd(dev->bgpio, &fd)) { + syslog(LOG_ERR, "peripheralman: failed to get the fd"); + return NULL; + } + + if (pipe(dev->isr_control_pipe)) { + syslog(LOG_ERR, "peripheralman: interrupt_handler: failed to create isr control pipe: %s", strerror(errno)); + close(fd); + return NULL; + } + + dev->isr_value_fp = fd; + + if (lang_func->java_attach_thread != NULL) { + if (dev->isr == lang_func->java_isr_callback) { + if (lang_func->java_attach_thread() != MRAA_SUCCESS) { + close(dev->isr_value_fp); + dev->isr_value_fp = -1; + return NULL; + } + } + } + + for (;;) { + mraa_result_t ret = mraa_pman_gpio_wait_interrupt(dev->isr_value_fp, dev->isr_control_pipe[0]); + if (ret == MRAA_SUCCESS) { + dev->isr(dev->isr_args); + } else { + if (fd != -1) { + close(dev->isr_value_fp); + dev->isr_value_fp = -1; + } + + if (lang_func->java_detach_thread != NULL && lang_func->java_delete_global_ref != NULL) { + if (dev->isr == lang_func->java_isr_callback) { + lang_func->java_delete_global_ref(dev->isr_args); + lang_func->java_detach_thread(); + } + } + + return NULL; + } + } +} + static mraa_result_t mraa_pman_gpio_isr_replace(mraa_gpio_context dev, mraa_gpio_edge_t edge, void (*fptr)(void*), void* args) { - return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; + if (dev->bgpio == NULL) { + syslog(LOG_ERR, "peripheralman: Invalid internal gpio handle"); + return -1; + } + + mraa_pman_gpio_edge_mode_replace(dev, edge); + + // we only allow one isr per mraa_gpio_context + if (dev->thread_id != 0) { + return MRAA_ERROR_NO_RESOURCES; + } + + dev->isr = fptr; + + /* Most UPM sensors use the C API, the Java global ref must be created here. */ + /* The reason for checking the callback function is internal callbacks. */ + if (lang_func->java_create_global_ref != NULL) { + if (dev->isr == lang_func->java_isr_callback) { + args = lang_func->java_create_global_ref(args); + } + } + + dev->isr_args = args; + pthread_create(&dev->thread_id, NULL, mraa_pman_gpio_interrupt_handler, (void*) dev); + + return MRAA_SUCCESS; } static mraa_result_t