peripheralman: implement gpio interrupt
Add gpio interrupt support for peripheral manager based on the existing implementation in gpio.c. Rewrite steps by using a global reference to lookup java isr routine using JNI methods and add exception check after every call. Free local reference class since it's not garbage collected and will lead to a memory leak. Signed-off-by: Sanrio Alvares <sanrio.alvares@intel.com> Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
This commit is contained in:
committed by
Brendan Le Foll
parent
5bbea8010e
commit
3d77c86634
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user