2015-08-28 12:35:04 -07:00
|
|
|
#include <jni.h>
|
2015-12-20 20:42:09 -08:00
|
|
|
#include <atomic>
|
2015-08-28 12:35:04 -07:00
|
|
|
#include <cassert>
|
2015-12-20 20:42:09 -08:00
|
|
|
#include <condition_variable>
|
|
|
|
|
#include <mutex>
|
2015-08-28 12:35:04 -07:00
|
|
|
#include <sstream>
|
2015-12-20 20:42:09 -08:00
|
|
|
#include <queue>
|
|
|
|
|
#include <thread>
|
2015-08-28 12:35:04 -07:00
|
|
|
|
|
|
|
|
#include "edu_wpi_first_wpilibj_networktables_NetworkTablesJNI.h"
|
|
|
|
|
#include "ntcore.h"
|
2015-12-20 20:42:09 -08:00
|
|
|
#include "atomic_static.h"
|
2015-12-28 08:28:24 -08:00
|
|
|
#include "SafeThread.h"
|
2016-06-10 22:24:42 -04:00
|
|
|
#include "llvm/ConvertUTF.h"
|
|
|
|
|
#include "llvm/SmallString.h"
|
|
|
|
|
#include "llvm/SmallVector.h"
|
2015-08-28 12:35:04 -07:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Globals and load/unload
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// Used for callback.
|
2015-09-05 11:05:02 -07:00
|
|
|
static JavaVM *jvm = nullptr;
|
2015-08-28 12:35:04 -07:00
|
|
|
static jclass booleanCls = nullptr;
|
|
|
|
|
static jclass doubleCls = nullptr;
|
|
|
|
|
static jclass stringCls = nullptr;
|
|
|
|
|
static jclass connectionInfoCls = nullptr;
|
2015-09-16 00:50:31 -07:00
|
|
|
static jclass entryInfoCls = nullptr;
|
2015-08-28 12:35:04 -07:00
|
|
|
static jclass keyNotDefinedEx = nullptr;
|
|
|
|
|
static jclass persistentEx = nullptr;
|
2016-04-08 13:31:35 -07:00
|
|
|
static jclass illegalArgEx = nullptr;
|
2015-12-20 20:42:09 -08:00
|
|
|
// Thread-attached environment for listener callbacks.
|
|
|
|
|
static JNIEnv *listenerEnv = nullptr;
|
|
|
|
|
|
|
|
|
|
static void ListenerOnStart() {
|
|
|
|
|
if (!jvm) return;
|
|
|
|
|
JNIEnv *env;
|
2015-12-28 08:28:24 -08:00
|
|
|
JavaVMAttachArgs args;
|
|
|
|
|
args.version = JNI_VERSION_1_2;
|
|
|
|
|
args.name = const_cast<char*>("NTListener");
|
|
|
|
|
args.group = nullptr;
|
|
|
|
|
if (jvm->AttachCurrentThreadAsDaemon(reinterpret_cast<void **>(&env),
|
|
|
|
|
&args) != JNI_OK)
|
2015-12-20 20:42:09 -08:00
|
|
|
return;
|
|
|
|
|
if (!env || !env->functions) return;
|
|
|
|
|
listenerEnv = env;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ListenerOnExit() {
|
|
|
|
|
listenerEnv = nullptr;
|
|
|
|
|
if (!jvm) return;
|
|
|
|
|
jvm->DetachCurrentThread();
|
|
|
|
|
}
|
2015-08-28 12:35:04 -07:00
|
|
|
|
2015-11-01 07:44:43 -08:00
|
|
|
extern "C" {
|
|
|
|
|
|
2015-08-28 13:52:16 -07:00
|
|
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
2015-08-28 12:35:04 -07:00
|
|
|
jvm = vm;
|
|
|
|
|
|
|
|
|
|
JNIEnv *env;
|
|
|
|
|
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK)
|
|
|
|
|
return JNI_ERR;
|
|
|
|
|
|
|
|
|
|
// Cache references to classes
|
|
|
|
|
jclass local;
|
|
|
|
|
|
|
|
|
|
local = env->FindClass("java/lang/Boolean");
|
|
|
|
|
if (!local) return JNI_ERR;
|
|
|
|
|
booleanCls = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!booleanCls) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
|
|
|
|
local = env->FindClass("java/lang/Double");
|
|
|
|
|
if (!local) return JNI_ERR;
|
|
|
|
|
doubleCls = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!doubleCls) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
|
|
|
|
local = env->FindClass("java/lang/String");
|
|
|
|
|
if (!local) return JNI_ERR;
|
|
|
|
|
stringCls = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!stringCls) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
|
|
|
|
local = env->FindClass("edu/wpi/first/wpilibj/networktables/ConnectionInfo");
|
|
|
|
|
if (!local) return JNI_ERR;
|
|
|
|
|
connectionInfoCls = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!connectionInfoCls) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
2015-09-16 00:50:31 -07:00
|
|
|
local = env->FindClass("edu/wpi/first/wpilibj/networktables/EntryInfo");
|
|
|
|
|
if (!local) return JNI_ERR;
|
|
|
|
|
entryInfoCls = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!entryInfoCls) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
local =
|
|
|
|
|
env->FindClass("edu/wpi/first/wpilibj/networktables/NetworkTableKeyNotDefined");
|
|
|
|
|
keyNotDefinedEx = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!keyNotDefinedEx) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
|
|
|
|
local =
|
|
|
|
|
env->FindClass("edu/wpi/first/wpilibj/networktables/PersistentException");
|
|
|
|
|
persistentEx = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!persistentEx) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
2016-04-08 13:31:35 -07:00
|
|
|
local = env->FindClass("java/lang/IllegalArgumentException");
|
|
|
|
|
if (!local) return JNI_ERR;
|
|
|
|
|
illegalArgEx = static_cast<jclass>(env->NewGlobalRef(local));
|
|
|
|
|
if (!illegalArgEx) return JNI_ERR;
|
|
|
|
|
env->DeleteLocalRef(local);
|
|
|
|
|
|
2015-12-20 20:42:09 -08:00
|
|
|
// Initial configuration of listener start/exit
|
|
|
|
|
nt::SetListenerOnStart(ListenerOnStart);
|
|
|
|
|
nt::SetListenerOnExit(ListenerOnExit);
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
return JNI_VERSION_1_6;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 13:52:16 -07:00
|
|
|
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
|
2015-08-28 12:35:04 -07:00
|
|
|
JNIEnv *env;
|
|
|
|
|
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK)
|
|
|
|
|
return;
|
|
|
|
|
// Delete global references
|
|
|
|
|
if (booleanCls) env->DeleteGlobalRef(booleanCls);
|
|
|
|
|
if (doubleCls) env->DeleteGlobalRef(doubleCls);
|
|
|
|
|
if (stringCls) env->DeleteGlobalRef(stringCls);
|
|
|
|
|
if (connectionInfoCls) env->DeleteGlobalRef(connectionInfoCls);
|
2015-09-16 00:50:31 -07:00
|
|
|
if (entryInfoCls) env->DeleteGlobalRef(entryInfoCls);
|
2015-08-28 12:35:04 -07:00
|
|
|
if (keyNotDefinedEx) env->DeleteGlobalRef(keyNotDefinedEx);
|
|
|
|
|
if (persistentEx) env->DeleteGlobalRef(persistentEx);
|
2016-04-08 13:31:35 -07:00
|
|
|
if (illegalArgEx) env->DeleteGlobalRef(illegalArgEx);
|
2015-09-05 11:05:02 -07:00
|
|
|
jvm = nullptr;
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
|
2015-11-01 07:44:43 -08:00
|
|
|
} // extern "C"
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
//
|
|
|
|
|
// Helper class to automatically clean up a local reference
|
|
|
|
|
//
|
|
|
|
|
template <typename T>
|
|
|
|
|
class JavaLocal {
|
|
|
|
|
public:
|
|
|
|
|
JavaLocal(JNIEnv *env, T obj) : m_env(env), m_obj(obj) {}
|
|
|
|
|
~JavaLocal() {
|
|
|
|
|
if (m_obj) m_env->DeleteLocalRef(m_obj);
|
|
|
|
|
}
|
|
|
|
|
operator T() { return m_obj; }
|
|
|
|
|
T obj() { return m_obj; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
JNIEnv *m_env;
|
|
|
|
|
T m_obj;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Helper class to create and clean up a global reference
|
|
|
|
|
//
|
|
|
|
|
template <typename T>
|
|
|
|
|
class JavaGlobal {
|
|
|
|
|
public:
|
|
|
|
|
JavaGlobal(JNIEnv *env, T obj)
|
|
|
|
|
: m_obj(static_cast<T>(env->NewGlobalRef(obj))) {}
|
|
|
|
|
~JavaGlobal() {
|
2015-09-14 22:00:22 -07:00
|
|
|
if (!jvm || nt::NotifierDestroyed()) return;
|
2015-08-28 12:35:04 -07:00
|
|
|
JNIEnv *env;
|
2016-01-01 19:05:00 -08:00
|
|
|
bool attached = false;
|
|
|
|
|
// don't attach and de-attach if already attached to a thread.
|
|
|
|
|
if (jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) ==
|
|
|
|
|
JNI_EDETACHED) {
|
|
|
|
|
if (jvm->AttachCurrentThread(reinterpret_cast<void **>(&env), nullptr) !=
|
|
|
|
|
JNI_OK)
|
|
|
|
|
return;
|
|
|
|
|
attached = true;
|
|
|
|
|
}
|
2015-09-05 11:05:02 -07:00
|
|
|
if (!env || !env->functions) return;
|
2015-08-28 12:35:04 -07:00
|
|
|
env->DeleteGlobalRef(m_obj);
|
2016-01-01 19:05:00 -08:00
|
|
|
if (attached) jvm->DetachCurrentThread();
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
operator T() { return m_obj; }
|
|
|
|
|
T obj() { return m_obj; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
T m_obj;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Helper class to create and clean up a weak global reference
|
|
|
|
|
//
|
|
|
|
|
template <typename T>
|
|
|
|
|
class JavaWeakGlobal {
|
|
|
|
|
public:
|
|
|
|
|
JavaWeakGlobal(JNIEnv *env, T obj)
|
|
|
|
|
: m_obj(static_cast<T>(env->NewWeakGlobalRef(obj))) {}
|
|
|
|
|
~JavaWeakGlobal() {
|
2015-09-14 22:00:22 -07:00
|
|
|
if (!jvm || nt::NotifierDestroyed()) return;
|
2015-08-28 12:35:04 -07:00
|
|
|
JNIEnv *env;
|
2016-01-01 19:05:00 -08:00
|
|
|
bool attached = false;
|
|
|
|
|
// don't attach and de-attach if already attached to a thread.
|
|
|
|
|
if (jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) ==
|
|
|
|
|
JNI_EDETACHED) {
|
|
|
|
|
if (jvm->AttachCurrentThread(reinterpret_cast<void **>(&env), nullptr) !=
|
|
|
|
|
JNI_OK)
|
|
|
|
|
return;
|
|
|
|
|
attached = true;
|
|
|
|
|
}
|
2015-09-05 11:05:02 -07:00
|
|
|
if (!env || !env->functions) return;
|
2015-08-28 12:35:04 -07:00
|
|
|
env->DeleteWeakGlobalRef(m_obj);
|
2016-01-01 19:05:00 -08:00
|
|
|
if (attached) jvm->DetachCurrentThread();
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
JavaLocal<T> obj(JNIEnv *env) {
|
|
|
|
|
return JavaLocal<T>(env, env->NewLocalRef(m_obj));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
T m_obj;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Conversions from Java objects to C++
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
class JavaStringRef {
|
|
|
|
|
public:
|
2016-06-10 22:24:42 -04:00
|
|
|
JavaStringRef(JNIEnv *env, jstring str) {
|
|
|
|
|
jsize size = env->GetStringLength(str);
|
|
|
|
|
const jchar *chars = env->GetStringChars(str, nullptr);
|
|
|
|
|
llvm::convertUTF16ToUTF8String(llvm::makeArrayRef(chars, size), m_str);
|
|
|
|
|
env->ReleaseStringChars(str, chars);
|
|
|
|
|
}
|
2015-08-28 12:35:04 -07:00
|
|
|
|
2016-06-10 22:24:42 -04:00
|
|
|
operator nt::StringRef() const { return m_str; }
|
|
|
|
|
nt::StringRef str() const { return m_str; }
|
|
|
|
|
const char* c_str() const { return m_str.data(); }
|
2015-08-28 12:35:04 -07:00
|
|
|
|
|
|
|
|
private:
|
2016-06-10 22:24:42 -04:00
|
|
|
llvm::SmallString<128> m_str;
|
2015-08-28 12:35:04 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class JavaByteRef {
|
|
|
|
|
public:
|
|
|
|
|
JavaByteRef(JNIEnv *env, jbyteArray jarr)
|
|
|
|
|
: m_env(env),
|
|
|
|
|
m_jarr(jarr),
|
|
|
|
|
m_elements(env->GetByteArrayElements(jarr, nullptr)),
|
|
|
|
|
m_size(env->GetArrayLength(jarr)) {}
|
|
|
|
|
~JavaByteRef() {
|
|
|
|
|
m_env->ReleaseByteArrayElements(m_jarr, m_elements, JNI_ABORT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operator nt::StringRef() const {
|
|
|
|
|
return nt::StringRef(reinterpret_cast<char *>(m_elements), m_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
JNIEnv *m_env;
|
|
|
|
|
jbyteArray m_jarr;
|
|
|
|
|
jbyte *m_elements;
|
|
|
|
|
size_t m_size;
|
|
|
|
|
};
|
|
|
|
|
|
2015-11-20 01:22:26 -08:00
|
|
|
class JavaByteRefBB {
|
|
|
|
|
public:
|
|
|
|
|
JavaByteRefBB(JNIEnv *env, jobject bb, int len)
|
2015-12-21 09:03:30 -08:00
|
|
|
: m_elements(env->GetDirectBufferAddress(bb)), m_size(len) {}
|
2015-11-20 01:22:26 -08:00
|
|
|
|
|
|
|
|
operator nt::StringRef() const {
|
|
|
|
|
return nt::StringRef(reinterpret_cast<char *>(m_elements), m_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void *m_elements;
|
|
|
|
|
size_t m_size;
|
|
|
|
|
};
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
std::shared_ptr<nt::Value> FromJavaRaw(JNIEnv *env, jbyteArray jarr) {
|
|
|
|
|
size_t len = env->GetArrayLength(jarr);
|
|
|
|
|
jbyte *elements =
|
|
|
|
|
static_cast<jbyte *>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
|
|
|
|
if (!elements) return nullptr;
|
|
|
|
|
auto rv = nt::Value::MakeRaw(
|
|
|
|
|
nt::StringRef(reinterpret_cast<char *>(elements), len));
|
|
|
|
|
env->ReleasePrimitiveArrayCritical(jarr, elements, JNI_ABORT);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 01:22:26 -08:00
|
|
|
std::shared_ptr<nt::Value> FromJavaRawBB(JNIEnv *env, jobject jbb, int len) {
|
|
|
|
|
void* elements = env->GetDirectBufferAddress(jbb);
|
|
|
|
|
if (!elements) return nullptr;
|
|
|
|
|
auto rv = nt::Value::MakeRaw(
|
|
|
|
|
nt::StringRef(reinterpret_cast<char *>(elements), len));
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
std::shared_ptr<nt::Value> FromJavaRpc(JNIEnv *env, jbyteArray jarr) {
|
|
|
|
|
size_t len = env->GetArrayLength(jarr);
|
|
|
|
|
jbyte *elements =
|
|
|
|
|
static_cast<jbyte *>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
|
|
|
|
if (!elements) return nullptr;
|
|
|
|
|
auto rv = nt::Value::MakeRpc(
|
|
|
|
|
nt::StringRef(reinterpret_cast<char *>(elements), len));
|
|
|
|
|
env->ReleasePrimitiveArrayCritical(jarr, elements, JNI_ABORT);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<nt::Value> FromJavaBooleanArray(JNIEnv *env,
|
|
|
|
|
jbooleanArray jarr) {
|
|
|
|
|
size_t len = env->GetArrayLength(jarr);
|
|
|
|
|
std::vector<int> arr;
|
|
|
|
|
arr.reserve(len);
|
|
|
|
|
jboolean *elements =
|
|
|
|
|
static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
|
|
|
|
if (!elements) return nullptr;
|
|
|
|
|
for (size_t i = 0; i < len; ++i) arr.push_back(elements[i]);
|
|
|
|
|
env->ReleasePrimitiveArrayCritical(jarr, elements, JNI_ABORT);
|
|
|
|
|
return nt::Value::MakeBooleanArray(arr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<nt::Value> FromJavaDoubleArray(JNIEnv *env, jdoubleArray jarr) {
|
|
|
|
|
size_t len = env->GetArrayLength(jarr);
|
|
|
|
|
jdouble *elements =
|
|
|
|
|
static_cast<jdouble *>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
|
|
|
|
if (!elements) return nullptr;
|
|
|
|
|
auto rv = nt::Value::MakeDoubleArray(nt::ArrayRef<double>(elements, len));
|
|
|
|
|
env->ReleasePrimitiveArrayCritical(jarr, elements, JNI_ABORT);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<nt::Value> FromJavaStringArray(JNIEnv *env, jobjectArray jarr) {
|
|
|
|
|
size_t len = env->GetArrayLength(jarr);
|
|
|
|
|
std::vector<std::string> arr;
|
|
|
|
|
arr.reserve(len);
|
|
|
|
|
for (size_t i = 0; i < len; ++i) {
|
|
|
|
|
JavaLocal<jstring> elem(
|
|
|
|
|
env, static_cast<jstring>(env->GetObjectArrayElement(jarr, i)));
|
|
|
|
|
if (!elem) return nullptr;
|
|
|
|
|
arr.push_back(JavaStringRef(env, elem).str());
|
|
|
|
|
}
|
|
|
|
|
return nt::Value::MakeStringArray(std::move(arr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Conversions from C++ to Java objects
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
static inline jstring ToJavaString(JNIEnv *env, nt::StringRef str) {
|
2016-06-10 22:24:42 -04:00
|
|
|
llvm::SmallVector<UTF16, 128> chars;
|
|
|
|
|
llvm::convertUTF8ToUTF16String(str, chars);
|
|
|
|
|
return env->NewString(chars.begin(), chars.size());
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static jbyteArray ToJavaByteArray(JNIEnv *env, nt::StringRef str) {
|
|
|
|
|
jbyteArray jarr = env->NewByteArray(str.size());
|
|
|
|
|
if (!jarr) return nullptr;
|
|
|
|
|
env->SetByteArrayRegion(jarr, 0, str.size(),
|
|
|
|
|
reinterpret_cast<const jbyte *>(str.data()));
|
|
|
|
|
return jarr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static jbooleanArray ToJavaBooleanArray(JNIEnv *env, nt::ArrayRef<int> arr)
|
|
|
|
|
{
|
|
|
|
|
jbooleanArray jarr = env->NewBooleanArray(arr.size());
|
|
|
|
|
if (!jarr) return nullptr;
|
|
|
|
|
jboolean *elements =
|
|
|
|
|
static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
|
|
|
|
if (!elements) return nullptr;
|
|
|
|
|
for (size_t i = 0; i < arr.size(); ++i)
|
|
|
|
|
elements[i] = arr[i];
|
|
|
|
|
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
|
|
|
|
return jarr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static jdoubleArray ToJavaDoubleArray(JNIEnv *env, nt::ArrayRef<double> arr)
|
|
|
|
|
{
|
|
|
|
|
jdoubleArray jarr = env->NewDoubleArray(arr.size());
|
|
|
|
|
if (!jarr) return nullptr;
|
|
|
|
|
env->SetDoubleArrayRegion(jarr, 0, arr.size(), arr.data());
|
|
|
|
|
return jarr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static jobjectArray ToJavaStringArray(JNIEnv *env,
|
|
|
|
|
nt::ArrayRef<std::string> arr) {
|
|
|
|
|
jobjectArray jarr = env->NewObjectArray(arr.size(), stringCls, nullptr);
|
|
|
|
|
if (!jarr) return nullptr;
|
|
|
|
|
for (size_t i = 0; i < arr.size(); ++i) {
|
|
|
|
|
JavaLocal<jstring> elem(env, env->NewStringUTF(arr[i].c_str()));
|
|
|
|
|
env->SetObjectArrayElement(jarr, i, elem.obj());
|
|
|
|
|
}
|
|
|
|
|
return jarr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static jobject ToJavaObject(JNIEnv *env, const nt::Value& value) {
|
|
|
|
|
static jmethodID booleanConstructor = nullptr;
|
|
|
|
|
static jmethodID doubleConstructor = nullptr;
|
|
|
|
|
if (!booleanConstructor)
|
|
|
|
|
booleanConstructor = env->GetMethodID(booleanCls, "<init>", "(Z)V");
|
|
|
|
|
if (!doubleConstructor)
|
|
|
|
|
doubleConstructor = env->GetMethodID(doubleCls, "<init>", "(D)V");
|
|
|
|
|
|
|
|
|
|
switch (value.type()) {
|
|
|
|
|
case NT_BOOLEAN:
|
|
|
|
|
return env->NewObject(booleanCls, booleanConstructor,
|
|
|
|
|
(jboolean)(value.GetBoolean() ? 1 : 0));
|
|
|
|
|
case NT_DOUBLE:
|
|
|
|
|
return env->NewObject(doubleCls, doubleConstructor,
|
|
|
|
|
(jdouble)value.GetDouble());
|
|
|
|
|
case NT_STRING:
|
|
|
|
|
return ToJavaString(env, value.GetString());
|
|
|
|
|
case NT_RAW:
|
|
|
|
|
return ToJavaByteArray(env, value.GetRaw());
|
|
|
|
|
case NT_BOOLEAN_ARRAY:
|
|
|
|
|
return ToJavaBooleanArray(env, value.GetBooleanArray());
|
|
|
|
|
case NT_DOUBLE_ARRAY:
|
|
|
|
|
return ToJavaDoubleArray(env, value.GetDoubleArray());
|
|
|
|
|
case NT_STRING_ARRAY:
|
|
|
|
|
return ToJavaStringArray(env, value.GetStringArray());
|
|
|
|
|
case NT_RPC:
|
|
|
|
|
return ToJavaByteArray(env, value.GetRpc());
|
|
|
|
|
default:
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static jobject ToJavaObject(JNIEnv *env, const nt::ConnectionInfo &info) {
|
|
|
|
|
static jmethodID constructor =
|
|
|
|
|
env->GetMethodID(connectionInfoCls, "<init>",
|
|
|
|
|
"(Ljava/lang/String;Ljava/lang/String;IJI)V");
|
|
|
|
|
JavaLocal<jstring> remote_id(env, ToJavaString(env, info.remote_id));
|
|
|
|
|
JavaLocal<jstring> remote_name(env, ToJavaString(env, info.remote_name));
|
|
|
|
|
return env->NewObject(connectionInfoCls, constructor, remote_id.obj(),
|
|
|
|
|
remote_name.obj(), (jint)info.remote_port,
|
|
|
|
|
(jlong)info.last_update, (jint)info.protocol_version);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-16 00:50:31 -07:00
|
|
|
static jobject ToJavaObject(JNIEnv *env, const nt::EntryInfo &info) {
|
|
|
|
|
static jmethodID constructor =
|
|
|
|
|
env->GetMethodID(entryInfoCls, "<init>", "(Ljava/lang/String;IIJ)V");
|
|
|
|
|
JavaLocal<jstring> name(env, ToJavaString(env, info.name));
|
|
|
|
|
return env->NewObject(entryInfoCls, constructor, name.obj(), (jint)info.type,
|
|
|
|
|
(jint)info.flags, (jlong)info.last_change);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
//
|
|
|
|
|
// Exception throwers
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
static void ThrowTableKeyNotDefined(JNIEnv *env, jstring key) {
|
|
|
|
|
static jmethodID constructor = nullptr;
|
|
|
|
|
if (!constructor)
|
|
|
|
|
constructor =
|
|
|
|
|
env->GetMethodID(keyNotDefinedEx, "<init>", "(Ljava/lang/String;)V");
|
|
|
|
|
jobject exception = env->NewObject(keyNotDefinedEx, constructor, key);
|
|
|
|
|
env->Throw(static_cast<jthrowable>(exception));
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-01 07:44:43 -08:00
|
|
|
extern "C" {
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: containsKey
|
|
|
|
|
* Signature: (Ljava/lang/String;)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_containsKey
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getType
|
|
|
|
|
* Signature: (Ljava/lang/String;)I
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getType
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val) return NT_UNASSIGNED;
|
|
|
|
|
return val->type();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putBoolean
|
|
|
|
|
* Signature: (Ljava/lang/String;Z)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putBoolean
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jboolean value)
|
|
|
|
|
{
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key),
|
2015-08-28 14:07:51 -07:00
|
|
|
nt::Value::MakeBoolean(value != JNI_FALSE));
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putDouble
|
|
|
|
|
* Signature: (Ljava/lang/String;D)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putDouble
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jdouble value)
|
|
|
|
|
{
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key),
|
|
|
|
|
nt::Value::MakeDouble(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putString
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/lang/String;)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putString
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jstring value)
|
|
|
|
|
{
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key),
|
|
|
|
|
nt::Value::MakeString(JavaStringRef(env, value)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putRaw
|
|
|
|
|
* Signature: (Ljava/lang/String;[B)Z
|
|
|
|
|
*/
|
2015-11-20 01:22:26 -08:00
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putRaw__Ljava_lang_String_2_3B
|
2015-08-28 12:35:04 -07:00
|
|
|
(JNIEnv *env, jclass, jstring key, jbyteArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaRaw(env, value);
|
|
|
|
|
if (!v) return false;
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 01:22:26 -08:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putRaw
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/nio/ByteBuffer;I)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putRaw__Ljava_lang_String_2Ljava_nio_ByteBuffer_2I
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jobject value, jint len)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaRawBB(env, value, len);
|
|
|
|
|
if (!v) return false;
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putBooleanArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[Z)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putBooleanArray
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jbooleanArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaBooleanArray(env, value);
|
|
|
|
|
if (!v) return false;
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putDoubleArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[D)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putDoubleArray
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jdoubleArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaDoubleArray(env, value);
|
|
|
|
|
if (!v) return false;
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: putStringArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[Ljava/lang/String;)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_putStringArray
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jobjectArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaStringArray(env, value);
|
|
|
|
|
if (!v) return false;
|
|
|
|
|
return nt::SetEntryValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutBoolean
|
|
|
|
|
* Signature: (Ljava/lang/String;Z)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutBoolean
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jboolean value)
|
|
|
|
|
{
|
2015-08-28 14:07:51 -07:00
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key), nt::Value::MakeBoolean(value != JNI_FALSE));
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutDouble
|
|
|
|
|
* Signature: (Ljava/lang/String;D)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutDouble
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jdouble value)
|
|
|
|
|
{
|
|
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key), nt::Value::MakeDouble(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutString
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutString
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jstring value)
|
|
|
|
|
{
|
|
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key),
|
|
|
|
|
nt::Value::MakeString(JavaStringRef(env, value)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutRaw
|
|
|
|
|
* Signature: (Ljava/lang/String;[B)V
|
|
|
|
|
*/
|
2015-11-20 01:22:26 -08:00
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutRaw__Ljava_lang_String_2_3B
|
2015-08-28 12:35:04 -07:00
|
|
|
(JNIEnv *env, jclass, jstring key, jbyteArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaRaw(env, value);
|
|
|
|
|
if (!v) return;
|
|
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 01:22:26 -08:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutRaw
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/nio/ByteBuffer;I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutRaw__Ljava_lang_String_2Ljava_nio_ByteBuffer_2I
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jobject value, jint len)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaRawBB(env, value, len);
|
|
|
|
|
if (!v) return;
|
|
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutBooleanArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[Z)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutBooleanArray
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jbooleanArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaBooleanArray(env, value);
|
|
|
|
|
if (!v) return;
|
|
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutDoubleArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[D)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutDoubleArray
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jdoubleArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaDoubleArray(env, value);
|
|
|
|
|
if (!v) return;
|
|
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: forcePutStringArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[Ljava/lang/String;)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_forcePutStringArray
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jobjectArray value)
|
|
|
|
|
{
|
|
|
|
|
auto v = FromJavaStringArray(env, value);
|
|
|
|
|
if (!v) return;
|
|
|
|
|
nt::SetEntryTypeValue(JavaStringRef(env, key), v);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 13:52:16 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getValue
|
|
|
|
|
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jobject JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getValue__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
2015-12-06 08:22:12 -08:00
|
|
|
if (!val) {
|
2015-08-28 13:52:16 -07:00
|
|
|
ThrowTableKeyNotDefined(env, key);
|
2015-08-28 17:17:20 -07:00
|
|
|
return nullptr;
|
2015-08-28 13:52:16 -07:00
|
|
|
}
|
|
|
|
|
return ToJavaObject(env, *val);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getBoolean
|
|
|
|
|
* Signature: (Ljava/lang/String;)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getBoolean__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsBoolean()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return val->GetBoolean();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getDouble
|
|
|
|
|
* Signature: (Ljava/lang/String;)D
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getDouble__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsDouble()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return val->GetDouble();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getString
|
|
|
|
|
* Signature: (Ljava/lang/String;)Ljava/lang/String;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jstring JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getString__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsString()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return ToJavaString(env, val->GetString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getRaw
|
|
|
|
|
* Signature: (Ljava/lang/String;)[B
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jbyteArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getRaw__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsRaw()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return ToJavaByteArray(env, val->GetRaw());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getBooleanArray
|
|
|
|
|
* Signature: (Ljava/lang/String;)[Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jbooleanArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getBooleanArray__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsBooleanArray()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return ToJavaBooleanArray(env, val->GetBooleanArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getDoubleArray
|
|
|
|
|
* Signature: (Ljava/lang/String;)[D
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jdoubleArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getDoubleArray__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsDoubleArray()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return ToJavaDoubleArray(env, val->GetDoubleArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getStringArray
|
|
|
|
|
* Signature: (Ljava/lang/String;)[Ljava/lang/String;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getStringArray__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsStringArray()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return ToJavaStringArray(env, val->GetStringArray());
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 13:52:16 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getValue
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jobject JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getValue__Ljava_lang_String_2Ljava_lang_Object_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jobject defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
2015-12-06 08:22:12 -08:00
|
|
|
if (!val) return defaultValue;
|
2015-08-28 13:52:16 -07:00
|
|
|
return ToJavaObject(env, *val);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getBoolean
|
|
|
|
|
* Signature: (Ljava/lang/String;Z)Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getBoolean__Ljava_lang_String_2Z
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jboolean defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsBoolean()) return defaultValue;
|
|
|
|
|
return val->GetBoolean();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getDouble
|
|
|
|
|
* Signature: (Ljava/lang/String;D)D
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getDouble__Ljava_lang_String_2D
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jdouble defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsDouble()) return defaultValue;
|
|
|
|
|
return val->GetDouble();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getString
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jstring JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getString__Ljava_lang_String_2Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jstring defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsString()) return defaultValue;
|
|
|
|
|
return ToJavaString(env, val->GetString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getRaw
|
|
|
|
|
* Signature: (Ljava/lang/String;[B)[B
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jbyteArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getRaw__Ljava_lang_String_2_3B
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jbyteArray defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsRaw()) return defaultValue;
|
|
|
|
|
return ToJavaByteArray(env, val->GetRaw());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getBooleanArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[Z)[Z
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jbooleanArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getBooleanArray__Ljava_lang_String_2_3Z
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jbooleanArray defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsBooleanArray()) return defaultValue;
|
|
|
|
|
return ToJavaBooleanArray(env, val->GetBooleanArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getDoubleArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[D)[D
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jdoubleArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getDoubleArray__Ljava_lang_String_2_3D
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jdoubleArray defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsDoubleArray()) return defaultValue;
|
|
|
|
|
return ToJavaDoubleArray(env, val->GetDoubleArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getStringArray
|
|
|
|
|
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getStringArray__Ljava_lang_String_2_3Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jobjectArray defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsStringArray()) return defaultValue;
|
|
|
|
|
return ToJavaStringArray(env, val->GetStringArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: setEntryFlags
|
|
|
|
|
* Signature: (Ljava/lang/String;I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setEntryFlags
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jint flags)
|
|
|
|
|
{
|
|
|
|
|
nt::SetEntryFlags(JavaStringRef(env, key), flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getEntryFlags
|
|
|
|
|
* Signature: (Ljava/lang/String;)I
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getEntryFlags
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
return nt::GetEntryFlags(JavaStringRef(env, key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: deleteEntry
|
|
|
|
|
* Signature: (Ljava/lang/String;)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_deleteEntry
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
nt::DeleteEntry(JavaStringRef(env, key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: deleteAllEntries
|
|
|
|
|
* Signature: ()V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_deleteAllEntries
|
|
|
|
|
(JNIEnv *, jclass)
|
|
|
|
|
{
|
|
|
|
|
nt::DeleteAllEntries();
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-16 00:50:31 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getEntries
|
|
|
|
|
* Signature: (Ljava/lang/String;I)[Ledu/wpi/first/wpilibj/networktables/EntryInfo;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getEntries
|
|
|
|
|
(JNIEnv *env, jclass, jstring prefix, jint types)
|
|
|
|
|
{
|
|
|
|
|
auto arr = nt::GetEntryInfo(JavaStringRef(env, prefix), types);
|
|
|
|
|
jobjectArray jarr = env->NewObjectArray(arr.size(), entryInfoCls, nullptr);
|
|
|
|
|
if (!jarr) return nullptr;
|
|
|
|
|
for (size_t i = 0; i < arr.size(); ++i) {
|
|
|
|
|
JavaLocal<jobject> jelem(env, ToJavaObject(env, arr[i]));
|
|
|
|
|
env->SetObjectArrayElement(jarr, i, jelem);
|
|
|
|
|
}
|
|
|
|
|
return jarr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: flush
|
|
|
|
|
* Signature: ()V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_flush
|
|
|
|
|
(JNIEnv *, jclass)
|
|
|
|
|
{
|
|
|
|
|
nt::Flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: addEntryListener
|
|
|
|
|
* Signature: (Ljava/lang/String;Ledu/wpi/first/wpilibj/networktables/NetworkTablesJNI/EntryListenerFunction;Z)I
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_addEntryListener
|
2015-09-25 11:54:17 -07:00
|
|
|
(JNIEnv *envouter, jclass, jstring prefix, jobject listener, jint flags)
|
2015-08-28 12:35:04 -07:00
|
|
|
{
|
|
|
|
|
// the shared pointer to the weak global will keep it around until the
|
|
|
|
|
// entry listener is destroyed
|
|
|
|
|
auto listener_global =
|
2015-09-15 21:32:51 -07:00
|
|
|
std::make_shared<JavaGlobal<jobject>>(envouter, listener);
|
2015-08-28 12:35:04 -07:00
|
|
|
|
|
|
|
|
// cls is a temporary here; cannot be used within callback functor
|
|
|
|
|
jclass cls = envouter->GetObjectClass(listener);
|
|
|
|
|
if (!cls) return 0;
|
|
|
|
|
|
|
|
|
|
// method ids, on the other hand, are safe to retain
|
|
|
|
|
jmethodID mid = envouter->GetMethodID(
|
2015-09-25 11:54:17 -07:00
|
|
|
cls, "apply", "(ILjava/lang/String;Ljava/lang/Object;I)V");
|
2015-08-28 12:35:04 -07:00
|
|
|
if (!mid) return 0;
|
|
|
|
|
|
|
|
|
|
return nt::AddEntryListener(
|
|
|
|
|
JavaStringRef(envouter, prefix),
|
|
|
|
|
[=](unsigned int uid, nt::StringRef name,
|
2015-09-25 11:54:17 -07:00
|
|
|
std::shared_ptr<nt::Value> value, unsigned int flags_) {
|
2015-12-20 20:42:09 -08:00
|
|
|
JNIEnv *env = listenerEnv;
|
2015-09-05 11:05:02 -07:00
|
|
|
if (!env || !env->functions) return;
|
2015-08-28 12:35:04 -07:00
|
|
|
|
2015-12-20 20:42:09 -08:00
|
|
|
// get the handler
|
|
|
|
|
auto handler = listener_global->obj();
|
|
|
|
|
|
|
|
|
|
// convert the value into the appropriate Java type
|
2016-01-01 19:05:00 -08:00
|
|
|
JavaLocal<jobject> jobj(env, ToJavaObject(env, *value));
|
2015-12-20 20:42:09 -08:00
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
|
env->ExceptionDescribe();
|
|
|
|
|
env->ExceptionClear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-01-01 19:05:00 -08:00
|
|
|
if (!jobj) return;
|
|
|
|
|
|
|
|
|
|
JavaLocal<jstring> jname(env, ToJavaString(env, name));
|
|
|
|
|
env->CallVoidMethod(handler, mid, (jint)uid, jname.obj(), jobj.obj(),
|
|
|
|
|
(jint)(flags_));
|
2015-12-20 20:42:09 -08:00
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
|
env->ExceptionDescribe();
|
|
|
|
|
env->ExceptionClear();
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
},
|
2015-09-25 11:54:17 -07:00
|
|
|
flags);
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: removeEntryListener
|
|
|
|
|
* Signature: (I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_removeEntryListener
|
|
|
|
|
(JNIEnv *, jclass, jint entryListenerUid)
|
|
|
|
|
{
|
|
|
|
|
nt::RemoveEntryListener(entryListenerUid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: addConnectionListener
|
|
|
|
|
* Signature: (Ledu/wpi/first/wpilibj/networktables/NetworkTablesJNI/ConnectionListenerFunction;Z)I
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_addConnectionListener
|
|
|
|
|
(JNIEnv *envouter, jclass, jobject listener, jboolean immediateNotify)
|
|
|
|
|
{
|
|
|
|
|
// the shared pointer to the weak global will keep it around until the
|
|
|
|
|
// entry listener is destroyed
|
|
|
|
|
auto listener_global =
|
2015-09-15 21:32:51 -07:00
|
|
|
std::make_shared<JavaGlobal<jobject>>(envouter, listener);
|
2015-08-28 12:35:04 -07:00
|
|
|
|
|
|
|
|
// cls is a temporary here; cannot be used within callback functor
|
|
|
|
|
jclass cls = envouter->GetObjectClass(listener);
|
|
|
|
|
if (!cls) return 0;
|
|
|
|
|
|
|
|
|
|
// method ids, on the other hand, are safe to retain
|
|
|
|
|
jmethodID mid = envouter->GetMethodID(
|
|
|
|
|
cls, "apply", "(IZLedu/wpi/first/wpilibj/networktables/ConnectionInfo;)V");
|
|
|
|
|
if (!mid) return 0;
|
|
|
|
|
|
|
|
|
|
return nt::AddConnectionListener(
|
|
|
|
|
[=](unsigned int uid, bool connected, const nt::ConnectionInfo& conn) {
|
2015-12-20 20:42:09 -08:00
|
|
|
JNIEnv *env = listenerEnv;
|
2015-09-05 11:05:02 -07:00
|
|
|
if (!env || !env->functions) return;
|
2015-08-28 12:35:04 -07:00
|
|
|
|
2015-12-20 20:42:09 -08:00
|
|
|
// get the handler
|
|
|
|
|
auto handler = listener_global->obj();
|
|
|
|
|
//if (!handler) goto done; // can happen due to weak reference
|
|
|
|
|
|
|
|
|
|
// convert into the appropriate Java type
|
2016-01-01 19:05:00 -08:00
|
|
|
JavaLocal<jobject> jobj(env, ToJavaObject(env, conn));
|
2015-12-20 20:42:09 -08:00
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
|
env->ExceptionDescribe();
|
|
|
|
|
env->ExceptionClear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-01-01 19:05:00 -08:00
|
|
|
if (!jobj) return;
|
|
|
|
|
|
2015-12-20 20:42:09 -08:00
|
|
|
env->CallVoidMethod(handler, mid, (jint)uid,
|
2016-01-01 19:05:00 -08:00
|
|
|
(jboolean)(connected ? 1 : 0), jobj.obj());
|
2015-12-20 20:42:09 -08:00
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
|
env->ExceptionDescribe();
|
|
|
|
|
env->ExceptionClear();
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
},
|
2015-08-28 14:07:51 -07:00
|
|
|
immediateNotify != JNI_FALSE);
|
2015-08-28 12:35:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: removeConnectionListener
|
|
|
|
|
* Signature: (I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_removeConnectionListener
|
|
|
|
|
(JNIEnv *, jclass, jint connListenerUid)
|
|
|
|
|
{
|
|
|
|
|
nt::RemoveConnectionListener(connListenerUid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getRpc
|
|
|
|
|
* Signature: (Ljava/lang/String;)[B
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jbyteArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getRpc__Ljava_lang_String_2
|
|
|
|
|
(JNIEnv *env, jclass, jstring key)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsRpc()) {
|
|
|
|
|
ThrowTableKeyNotDefined(env, key);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return ToJavaByteArray(env, val->GetRpc());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getRpc
|
|
|
|
|
* Signature: (Ljava/lang/String;[B)[B
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jbyteArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getRpc__Ljava_lang_String_2_3B
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jbyteArray defaultValue)
|
|
|
|
|
{
|
|
|
|
|
auto val = nt::GetEntryValue(JavaStringRef(env, key));
|
|
|
|
|
if (!val || !val->IsRpc()) return defaultValue;
|
|
|
|
|
return ToJavaByteArray(env, val->GetRpc());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: callRpc
|
|
|
|
|
* Signature: (Ljava/lang/String;[B)I
|
|
|
|
|
*/
|
2015-11-20 01:22:26 -08:00
|
|
|
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_callRpc__Ljava_lang_String_2_3B
|
2015-08-28 12:35:04 -07:00
|
|
|
(JNIEnv *env, jclass, jstring key, jbyteArray params)
|
|
|
|
|
{
|
|
|
|
|
return nt::CallRpc(JavaStringRef(env, key), JavaByteRef(env, params));
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 01:22:26 -08:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: callRpc
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/nio/ByteBuffer;I)I
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_callRpc__Ljava_lang_String_2Ljava_nio_ByteBuffer_2I
|
|
|
|
|
(JNIEnv *env, jclass, jstring key, jobject params, jint params_len)
|
|
|
|
|
{
|
|
|
|
|
return nt::CallRpc(JavaStringRef(env, key),
|
|
|
|
|
JavaByteRefBB(env, params, params_len));
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: setNetworkIdentity
|
|
|
|
|
* Signature: (Ljava/lang/String;)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setNetworkIdentity
|
|
|
|
|
(JNIEnv *env, jclass, jstring name)
|
|
|
|
|
{
|
|
|
|
|
nt::SetNetworkIdentity(JavaStringRef(env, name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: startServer
|
|
|
|
|
* Signature: (Ljava/lang/String;Ljava/lang/String;I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_startServer
|
|
|
|
|
(JNIEnv *env, jclass, jstring persistFilename, jstring listenAddress,
|
|
|
|
|
jint port)
|
|
|
|
|
{
|
|
|
|
|
nt::StartServer(JavaStringRef(env, persistFilename),
|
|
|
|
|
JavaStringRef(env, listenAddress).c_str(), port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: stopServer
|
|
|
|
|
* Signature: ()V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_stopServer
|
|
|
|
|
(JNIEnv *, jclass)
|
|
|
|
|
{
|
|
|
|
|
nt::StopServer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: startClient
|
|
|
|
|
* Signature: (Ljava/lang/String;I)V
|
|
|
|
|
*/
|
2016-04-08 13:31:35 -07:00
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_startClient__Ljava_lang_String_2I
|
2015-08-28 12:35:04 -07:00
|
|
|
(JNIEnv *env, jclass, jstring serverName, jint port)
|
|
|
|
|
{
|
|
|
|
|
nt::StartClient(JavaStringRef(env, serverName).c_str(), port);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 13:31:35 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: startClient
|
|
|
|
|
* Signature: ([Ljava/lang/String;[I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_startClient___3Ljava_lang_String_2_3I
|
|
|
|
|
(JNIEnv *env, jclass, jobjectArray serverNames, jintArray ports)
|
|
|
|
|
{
|
|
|
|
|
int len = env->GetArrayLength(serverNames);
|
|
|
|
|
if (len != env->GetArrayLength(ports)) {
|
|
|
|
|
env->ThrowNew(illegalArgEx,
|
|
|
|
|
"serverNames and ports arrays must be the same size");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
jint* portInts = env->GetIntArrayElements(ports, nullptr);
|
|
|
|
|
if (!portInts) return;
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> names;
|
|
|
|
|
std::vector<std::pair<nt::StringRef, unsigned int>> servers;
|
|
|
|
|
names.reserve(len);
|
|
|
|
|
servers.reserve(len);
|
|
|
|
|
for (int i = 0; i < len; ++i) {
|
|
|
|
|
JavaLocal<jstring> elem(
|
|
|
|
|
env, static_cast<jstring>(env->GetObjectArrayElement(serverNames, i)));
|
|
|
|
|
if (!elem) {
|
|
|
|
|
env->ThrowNew(illegalArgEx, "null string in serverNames");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
names.emplace_back(JavaStringRef(env, elem).str());
|
|
|
|
|
servers.emplace_back(std::make_pair(nt::StringRef(names.back()),
|
|
|
|
|
portInts[i]));
|
|
|
|
|
}
|
|
|
|
|
env->ReleaseIntArrayElements(ports, portInts, JNI_ABORT);
|
|
|
|
|
nt::StartClient(servers);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: stopClient
|
|
|
|
|
* Signature: ()V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_stopClient
|
|
|
|
|
(JNIEnv *, jclass)
|
|
|
|
|
{
|
|
|
|
|
nt::StopClient();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: setUpdateRate
|
|
|
|
|
* Signature: (D)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setUpdateRate
|
|
|
|
|
(JNIEnv *, jclass, jdouble interval)
|
|
|
|
|
{
|
|
|
|
|
nt::SetUpdateRate(interval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: getConnections
|
|
|
|
|
* Signature: ()[Ledu/wpi/first/wpilibj/networktables/ConnectionInfo;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getConnections
|
|
|
|
|
(JNIEnv *env, jclass)
|
|
|
|
|
{
|
|
|
|
|
auto arr = nt::GetConnections();
|
|
|
|
|
jobjectArray jarr =
|
|
|
|
|
env->NewObjectArray(arr.size(), connectionInfoCls, nullptr);
|
|
|
|
|
if (!jarr) return nullptr;
|
|
|
|
|
for (size_t i = 0; i < arr.size(); ++i) {
|
|
|
|
|
JavaLocal<jobject> jelem(env, ToJavaObject(env, arr[i]));
|
|
|
|
|
env->SetObjectArrayElement(jarr, i, jelem);
|
|
|
|
|
}
|
|
|
|
|
return jarr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: savePersistent
|
|
|
|
|
* Signature: (Ljava/lang/String;)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_savePersistent
|
|
|
|
|
(JNIEnv *env, jclass, jstring filename)
|
|
|
|
|
{
|
|
|
|
|
const char *err = nt::SavePersistent(JavaStringRef(env, filename));
|
|
|
|
|
if (err) env->ThrowNew(persistentEx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: loadPersistent
|
|
|
|
|
* Signature: (Ljava/lang/String;)[Ljava/lang/String;
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_loadPersistent
|
|
|
|
|
(JNIEnv *env, jclass, jstring filename)
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string> warns;
|
|
|
|
|
const char *err = nt::LoadPersistent(JavaStringRef(env, filename),
|
|
|
|
|
[&](size_t line, const char *msg) {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << line << ": " << msg;
|
|
|
|
|
warns.push_back(oss.str());
|
|
|
|
|
});
|
|
|
|
|
if (err) {
|
|
|
|
|
env->ThrowNew(persistentEx, err);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return ToJavaStringArray(env, warns);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: now
|
|
|
|
|
* Signature: ()J
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_now
|
|
|
|
|
(JNIEnv *, jclass)
|
|
|
|
|
{
|
|
|
|
|
return nt::Now();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-20 20:42:09 -08:00
|
|
|
} // extern "C"
|
|
|
|
|
|
|
|
|
|
// Thread where log 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.
|
2015-12-28 08:28:24 -08:00
|
|
|
class LoggerThreadJNI : public nt::SafeThread {
|
2015-12-20 20:42:09 -08:00
|
|
|
public:
|
2015-12-28 08:28:24 -08:00
|
|
|
void Main();
|
2015-12-20 20:42:09 -08:00
|
|
|
|
|
|
|
|
struct LogMessage {
|
|
|
|
|
LogMessage(unsigned int level_, const char* file_, unsigned int line_,
|
|
|
|
|
const char* msg_)
|
|
|
|
|
: level(level_), file(file_), line(line_), msg(msg_) {}
|
|
|
|
|
unsigned int level;
|
|
|
|
|
const char* file;
|
|
|
|
|
unsigned int line;
|
|
|
|
|
std::string msg;
|
|
|
|
|
};
|
|
|
|
|
std::queue<LogMessage> m_queue;
|
|
|
|
|
jobject m_func = nullptr;
|
|
|
|
|
jmethodID m_mid;
|
|
|
|
|
};
|
|
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
class LoggerJNI : public nt::SafeThreadOwner<LoggerThreadJNI> {
|
|
|
|
|
public:
|
|
|
|
|
static LoggerJNI& GetInstance() {
|
|
|
|
|
ATOMIC_STATIC(LoggerJNI, instance);
|
|
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
|
|
|
|
|
void Log(unsigned int level, const char* file, unsigned int line,
|
|
|
|
|
const char* msg);
|
2015-12-20 21:06:17 -08:00
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
private:
|
|
|
|
|
ATOMIC_STATIC_DECL(LoggerJNI)
|
|
|
|
|
};
|
2015-12-20 20:55:36 -08:00
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
ATOMIC_STATIC_INIT(LoggerJNI)
|
2015-12-20 20:42:09 -08:00
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
void LoggerJNI::SetFunc(JNIEnv* env, jobject func, jmethodID mid) {
|
|
|
|
|
auto thr = GetThread();
|
|
|
|
|
if (!thr) return;
|
2015-12-20 20:42:09 -08:00
|
|
|
// free global reference
|
2015-12-28 08:28:24 -08:00
|
|
|
if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
|
2015-12-20 20:42:09 -08:00
|
|
|
// create global reference
|
2015-12-28 08:28:24 -08:00
|
|
|
thr->m_func = env->NewGlobalRef(func);
|
|
|
|
|
thr->m_mid = mid;
|
2015-12-20 20:42:09 -08:00
|
|
|
}
|
|
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
void LoggerJNI::Log(unsigned int level, const char *file, unsigned int line,
|
|
|
|
|
const char *msg) {
|
|
|
|
|
auto thr = GetThread();
|
|
|
|
|
if (!thr) return;
|
|
|
|
|
thr->m_queue.emplace(level, file, line, msg);
|
|
|
|
|
thr->m_cond.notify_one();
|
2015-12-20 20:42:09 -08:00
|
|
|
}
|
|
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
void LoggerThreadJNI::Main() {
|
2015-12-20 20:42:09 -08:00
|
|
|
JNIEnv *env;
|
2015-12-28 08:28:24 -08:00
|
|
|
JavaVMAttachArgs args;
|
|
|
|
|
args.version = JNI_VERSION_1_2;
|
|
|
|
|
args.name = const_cast<char*>("NTLogger");
|
|
|
|
|
args.group = nullptr;
|
|
|
|
|
jint rs = jvm->AttachCurrentThreadAsDaemon((void**)&env, &args);
|
2015-12-20 20:42:09 -08:00
|
|
|
if (rs != JNI_OK) return;
|
|
|
|
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(m_mutex);
|
|
|
|
|
while (m_active) {
|
2015-12-28 08:28:24 -08:00
|
|
|
m_cond.wait(lock, [&] { return !(m_active && m_queue.empty()); });
|
2015-12-20 20:42:09 -08:00
|
|
|
if (!m_active) break;
|
|
|
|
|
while (!m_queue.empty()) {
|
|
|
|
|
if (!m_active) break;
|
|
|
|
|
auto item = std::move(m_queue.front());
|
|
|
|
|
m_queue.pop();
|
|
|
|
|
auto func = m_func;
|
|
|
|
|
auto mid = m_mid;
|
|
|
|
|
lock.unlock(); // don't hold mutex during callback execution
|
2015-12-28 08:28:24 -08:00
|
|
|
{
|
|
|
|
|
JavaLocal<jstring> file(env, ToJavaString(env, item.file));
|
|
|
|
|
JavaLocal<jstring> msg(env, ToJavaString(env, item.msg));
|
|
|
|
|
env->CallVoidMethod(func, mid, (jint)item.level, file.obj(),
|
|
|
|
|
(jint)item.line, msg.obj());
|
|
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
|
env->ExceptionDescribe();
|
|
|
|
|
env->ExceptionClear();
|
|
|
|
|
}
|
2015-12-20 20:42:09 -08:00
|
|
|
}
|
|
|
|
|
lock.lock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (jvm) jvm->DetachCurrentThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
2015-08-28 12:35:04 -07:00
|
|
|
/*
|
|
|
|
|
* Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI
|
|
|
|
|
* Method: setLogger
|
|
|
|
|
* Signature: (Ledu/wpi/first/wpilibj/networktables/NetworkTablesJNI/LoggerFunction;I)V
|
|
|
|
|
*/
|
|
|
|
|
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setLogger
|
2015-12-20 20:42:09 -08:00
|
|
|
(JNIEnv *env, jclass, jobject func, jint minLevel)
|
2015-08-28 12:35:04 -07:00
|
|
|
{
|
|
|
|
|
// cls is a temporary here; cannot be used within callback functor
|
2015-12-20 20:42:09 -08:00
|
|
|
jclass cls = env->GetObjectClass(func);
|
2015-08-28 12:35:04 -07:00
|
|
|
if (!cls) return;
|
|
|
|
|
|
|
|
|
|
// method ids, on the other hand, are safe to retain
|
2015-12-20 20:42:09 -08:00
|
|
|
jmethodID mid = env->GetMethodID(
|
2015-08-28 12:35:04 -07:00
|
|
|
cls, "apply", "(ILjava/lang/String;ILjava/lang/String;)V");
|
|
|
|
|
if (!mid) return;
|
|
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
auto& logger = LoggerJNI::GetInstance();
|
|
|
|
|
logger.Start();
|
|
|
|
|
logger.SetFunc(env, func, mid);
|
2015-08-28 12:35:04 -07:00
|
|
|
|
2015-12-20 20:42:09 -08:00
|
|
|
nt::SetLogger(
|
|
|
|
|
[](unsigned int level, const char *file, unsigned int line,
|
|
|
|
|
const char *msg) {
|
2015-12-28 08:28:24 -08:00
|
|
|
LoggerJNI::GetInstance().Log(level, file, line, msg);
|
2015-08-28 12:35:04 -07:00
|
|
|
},
|
|
|
|
|
minLevel);
|
|
|
|
|
}
|
2015-11-01 07:44:43 -08:00
|
|
|
|
|
|
|
|
} // extern "C"
|