2016-01-02 03:02:34 -08:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2020-02-18 20:41:42 -08:00
|
|
|
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
|
2016-01-02 03:02:34 -08:00
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
2016-05-20 17:30:37 -07:00
|
|
|
#include <jni.h>
|
2018-05-13 17:09:56 -07:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
#include <atomic>
|
2018-05-13 17:09:56 -07:00
|
|
|
#include <cassert>
|
2015-12-17 16:19:44 -08:00
|
|
|
#include <thread>
|
2017-11-13 09:51:48 -08:00
|
|
|
|
2018-04-29 23:33:19 -07:00
|
|
|
#include <wpi/SafeThread.h>
|
|
|
|
|
#include <wpi/mutex.h>
|
2017-11-13 09:51:48 -08:00
|
|
|
|
2015-11-01 09:11:52 -08:00
|
|
|
#include "HALUtil.h"
|
2018-09-20 21:59:46 -07:00
|
|
|
#include "edu_wpi_first_hal_InterruptJNI.h"
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/Interrupts.h"
|
2014-08-04 14:19:01 -04:00
|
|
|
|
2020-06-26 17:12:55 -07:00
|
|
|
using namespace hal;
|
2016-10-31 23:04:49 -07:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
// Thread where callbacks are actually performed.
|
|
|
|
|
//
|
|
|
|
|
// JNI's AttachCurrentThread() creates a Java Thread object on every
|
|
|
|
|
// invocation, which is both time inefficient and causes issues with Eclipse
|
|
|
|
|
// (which tries to keep a thread list up-to-date and thus gets swamped).
|
|
|
|
|
//
|
|
|
|
|
// Instead, this class attaches just once. When a hardware notification
|
|
|
|
|
// occurs, a condition variable wakes up this thread and this thread actually
|
|
|
|
|
// makes the call into Java.
|
|
|
|
|
//
|
|
|
|
|
// We don't want to use a FIFO here. If the user code takes too long to
|
|
|
|
|
// process, we will just ignore the redundant wakeup.
|
2016-10-23 14:18:46 -07:00
|
|
|
class InterruptThreadJNI : public wpi::SafeThread {
|
2015-12-17 16:19:44 -08:00
|
|
|
public:
|
|
|
|
|
void Main();
|
|
|
|
|
|
|
|
|
|
bool m_notify = false;
|
|
|
|
|
uint32_t m_mask = 0;
|
|
|
|
|
jobject m_func = nullptr;
|
|
|
|
|
jmethodID m_mid;
|
|
|
|
|
jobject m_param = nullptr;
|
|
|
|
|
};
|
|
|
|
|
|
2016-10-23 14:18:46 -07:00
|
|
|
class InterruptJNI : public wpi::SafeThreadOwner<InterruptThreadJNI> {
|
2015-12-17 16:19:44 -08:00
|
|
|
public:
|
|
|
|
|
void SetFunc(JNIEnv* env, jobject func, jmethodID mid, jobject param);
|
|
|
|
|
|
|
|
|
|
void Notify(uint32_t mask) {
|
|
|
|
|
auto thr = GetThread();
|
|
|
|
|
if (!thr) return;
|
|
|
|
|
thr->m_notify = true;
|
|
|
|
|
thr->m_mask = mask;
|
|
|
|
|
thr->m_cond.notify_one();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void InterruptJNI::SetFunc(JNIEnv* env, jobject func, jmethodID mid,
|
|
|
|
|
jobject param) {
|
|
|
|
|
auto thr = GetThread();
|
|
|
|
|
if (!thr) return;
|
|
|
|
|
// free global references
|
|
|
|
|
if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
|
|
|
|
|
if (thr->m_param) env->DeleteGlobalRef(thr->m_param);
|
|
|
|
|
// create global references
|
|
|
|
|
thr->m_func = env->NewGlobalRef(func);
|
|
|
|
|
thr->m_param = param ? env->NewGlobalRef(param) : nullptr;
|
|
|
|
|
thr->m_mid = mid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InterruptThreadJNI::Main() {
|
2016-05-20 17:30:37 -07:00
|
|
|
JNIEnv* env;
|
2015-12-17 16:19:44 -08:00
|
|
|
JavaVMAttachArgs args;
|
|
|
|
|
args.version = JNI_VERSION_1_2;
|
|
|
|
|
args.name = const_cast<char*>("Interrupt");
|
|
|
|
|
args.group = nullptr;
|
2018-05-13 17:09:56 -07:00
|
|
|
jint rs = GetJVM()->AttachCurrentThreadAsDaemon(
|
|
|
|
|
reinterpret_cast<void**>(&env), &args);
|
2015-12-17 16:19:44 -08:00
|
|
|
if (rs != JNI_OK) return;
|
|
|
|
|
|
2019-07-07 19:17:14 -07:00
|
|
|
std::unique_lock lock(m_mutex);
|
2015-12-17 16:19:44 -08:00
|
|
|
while (m_active) {
|
|
|
|
|
m_cond.wait(lock, [&] { return !m_active || m_notify; });
|
|
|
|
|
if (!m_active) break;
|
|
|
|
|
m_notify = false;
|
|
|
|
|
if (!m_func) continue;
|
|
|
|
|
jobject func = m_func;
|
|
|
|
|
jmethodID mid = m_mid;
|
|
|
|
|
uint32_t mask = m_mask;
|
|
|
|
|
jobject param = m_param;
|
|
|
|
|
lock.unlock(); // don't hold mutex during callback execution
|
2016-08-24 21:39:16 -07:00
|
|
|
env->CallVoidMethod(func, mid, static_cast<jint>(mask), param);
|
2015-12-17 16:19:44 -08:00
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
|
env->ExceptionDescribe();
|
|
|
|
|
env->ExceptionClear();
|
|
|
|
|
}
|
|
|
|
|
lock.lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// free global references
|
|
|
|
|
if (m_func) env->DeleteGlobalRef(m_func);
|
|
|
|
|
if (m_param) env->DeleteGlobalRef(m_param);
|
|
|
|
|
|
2018-04-29 13:29:07 -07:00
|
|
|
GetJVM()->DetachCurrentThread();
|
2015-12-17 16:19:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void interruptHandler(uint32_t mask, void* param) {
|
2016-08-24 21:39:16 -07:00
|
|
|
static_cast<InterruptJNI*>(param)->Notify(mask);
|
2015-12-17 16:19:44 -08:00
|
|
|
}
|
|
|
|
|
|
2015-11-01 09:11:52 -08:00
|
|
|
extern "C" {
|
2014-01-06 09:27:51 -05:00
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: initializeInterrupts
|
2016-06-20 23:22:49 -07:00
|
|
|
* Signature: (Z)I
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2016-06-20 23:22:49 -07:00
|
|
|
JNIEXPORT jint JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_initializeInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jboolean watcher)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(watcher, &status);
|
2014-08-04 14:19:01 -04:00
|
|
|
|
2016-09-29 20:18:40 -07:00
|
|
|
CheckStatusForceThrow(env, status);
|
2016-06-20 23:22:49 -07:00
|
|
|
return (jint)interrupt;
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: cleanInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
* Signature: (I)V
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2016-05-20 17:30:37 -07:00
|
|
|
JNIEXPORT void JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_cleanInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2018-05-24 17:02:13 -07:00
|
|
|
auto param =
|
|
|
|
|
HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle, &status);
|
|
|
|
|
if (param) {
|
|
|
|
|
delete static_cast<InterruptJNI*>(param);
|
|
|
|
|
}
|
2014-01-06 09:27:51 -05:00
|
|
|
|
2016-06-20 23:22:49 -07:00
|
|
|
// ignore status, as an invalid handle just needs to be ignored.
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: waitForInterrupt
|
2018-05-13 17:09:56 -07:00
|
|
|
* Signature: (IDZ)I
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2017-07-08 07:48:27 -07:00
|
|
|
JNIEXPORT jint JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_waitForInterrupt
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle, jdouble timeout,
|
|
|
|
|
jboolean ignorePrevious)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2016-09-06 00:01:45 -07:00
|
|
|
int32_t result = HAL_WaitForInterrupt((HAL_InterruptHandle)interruptHandle,
|
|
|
|
|
timeout, ignorePrevious, &status);
|
2014-01-06 09:27:51 -05:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
CheckStatus(env, status);
|
|
|
|
|
return result;
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: enableInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
* Signature: (I)V
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2016-05-20 17:30:37 -07:00
|
|
|
JNIEXPORT void JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_enableInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_EnableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
|
2014-08-04 14:19:01 -04:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
CheckStatus(env, status);
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: disableInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
* Signature: (I)V
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2016-05-20 17:30:37 -07:00
|
|
|
JNIEXPORT void JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_disableInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_DisableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
|
2014-08-04 14:19:01 -04:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
CheckStatus(env, status);
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2016-07-09 01:12:37 -07:00
|
|
|
* Method: readInterruptRisingTimestamp
|
2018-11-15 21:22:03 -08:00
|
|
|
* Signature: (I)J
|
2014-10-05 17:17:59 -04:00
|
|
|
*/
|
2018-11-15 21:22:03 -08:00
|
|
|
JNIEXPORT jlong JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_readInterruptRisingTimestamp
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2018-11-15 21:22:03 -08:00
|
|
|
jlong timeStamp = HAL_ReadInterruptRisingTimestamp(
|
2018-05-13 17:09:56 -07:00
|
|
|
(HAL_InterruptHandle)interruptHandle, &status);
|
2014-10-05 17:17:59 -04:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
CheckStatus(env, status);
|
|
|
|
|
return timeStamp;
|
2014-10-05 17:17:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2016-07-09 01:12:37 -07:00
|
|
|
* Method: readInterruptFallingTimestamp
|
2018-11-15 21:22:03 -08:00
|
|
|
* Signature: (I)J
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2018-11-15 21:22:03 -08:00
|
|
|
JNIEXPORT jlong JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_readInterruptFallingTimestamp
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2018-11-15 21:22:03 -08:00
|
|
|
jlong timeStamp = HAL_ReadInterruptFallingTimestamp(
|
2018-05-13 17:09:56 -07:00
|
|
|
(HAL_InterruptHandle)interruptHandle, &status);
|
2014-01-06 09:27:51 -05:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
CheckStatus(env, status);
|
|
|
|
|
return timeStamp;
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: requestInterrupts
|
2016-07-07 21:43:55 -07:00
|
|
|
* Signature: (III)V
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2016-05-20 17:30:37 -07:00
|
|
|
JNIEXPORT void JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_requestInterrupts
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle, jint digitalSourceHandle,
|
|
|
|
|
jint analogTriggerType)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2018-05-13 17:09:56 -07:00
|
|
|
HAL_RequestInterrupts((HAL_InterruptHandle)interruptHandle,
|
|
|
|
|
(HAL_Handle)digitalSourceHandle,
|
|
|
|
|
(HAL_AnalogTriggerType)analogTriggerType, &status);
|
2015-12-17 16:19:44 -08:00
|
|
|
|
|
|
|
|
CheckStatus(env, status);
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: attachInterruptHandler
|
2018-05-13 17:09:56 -07:00
|
|
|
* Signature: (ILjava/lang/Object;Ljava/lang/Object;)V
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2016-05-20 17:30:37 -07:00
|
|
|
JNIEXPORT void JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_attachInterruptHandler
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle, jobject handler, jobject param)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
jclass cls = env->GetObjectClass(handler);
|
|
|
|
|
if (cls == 0) {
|
|
|
|
|
assert(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
jmethodID mid = env->GetMethodID(cls, "apply", "(ILjava/lang/Object;)V");
|
|
|
|
|
if (mid == 0) {
|
|
|
|
|
assert(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InterruptJNI* intr = new InterruptJNI;
|
|
|
|
|
intr->Start();
|
|
|
|
|
intr->SetFunc(env, handler, mid, param);
|
|
|
|
|
|
|
|
|
|
int32_t status = 0;
|
2018-05-13 17:09:56 -07:00
|
|
|
HAL_AttachInterruptHandler((HAL_InterruptHandle)interruptHandle,
|
|
|
|
|
interruptHandler, intr, &status);
|
2015-12-17 16:19:44 -08:00
|
|
|
|
|
|
|
|
CheckStatus(env, status);
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-09-20 21:59:46 -07:00
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
2014-01-06 09:27:51 -05:00
|
|
|
* Method: setInterruptUpSourceEdge
|
2018-05-13 17:09:56 -07:00
|
|
|
* Signature: (IZZ)V
|
2014-01-06 09:27:51 -05:00
|
|
|
*/
|
2016-05-20 17:30:37 -07:00
|
|
|
JNIEXPORT void JNICALL
|
2018-09-20 21:59:46 -07:00
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_setInterruptUpSourceEdge
|
2018-05-13 17:09:56 -07:00
|
|
|
(JNIEnv* env, jclass, jint interruptHandle, jboolean risingEdge,
|
|
|
|
|
jboolean fallingEdge)
|
|
|
|
|
{
|
2015-12-17 16:19:44 -08:00
|
|
|
int32_t status = 0;
|
2018-05-13 17:09:56 -07:00
|
|
|
HAL_SetInterruptUpSourceEdge((HAL_InterruptHandle)interruptHandle, risingEdge,
|
|
|
|
|
fallingEdge, &status);
|
2014-01-06 09:27:51 -05:00
|
|
|
|
2015-12-17 16:19:44 -08:00
|
|
|
CheckStatus(env, status);
|
2014-01-06 09:27:51 -05:00
|
|
|
}
|
2015-11-01 09:11:52 -08:00
|
|
|
|
2020-02-18 20:41:42 -08:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_hal_InterruptJNI
|
|
|
|
|
* Method: releaseWaitingInterrupt
|
|
|
|
|
* Signature: (I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL
|
|
|
|
|
Java_edu_wpi_first_hal_InterruptJNI_releaseWaitingInterrupt
|
|
|
|
|
(JNIEnv* env, jclass, jint interruptHandle)
|
|
|
|
|
{
|
|
|
|
|
int32_t status = 0;
|
|
|
|
|
HAL_ReleaseWaitingInterrupt((HAL_InterruptHandle)interruptHandle, &status);
|
|
|
|
|
|
|
|
|
|
CheckStatus(env, status);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-01 09:11:52 -08:00
|
|
|
} // extern "C"
|