aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/JAntNative.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/JAntNative.cpp')
-rw-r--r--src/common/JAntNative.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/src/common/JAntNative.cpp b/src/common/JAntNative.cpp
new file mode 100644
index 0000000..2e3beb0
--- /dev/null
+++ b/src/common/JAntNative.cpp
@@ -0,0 +1,366 @@
+/*
+ * ANT Stack
+ *
+ * Copyright 2009 Dynastream Innovations
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*******************************************************************************\
+*
+* FILE NAME: JAntNative.cpp
+*
+* BRIEF:
+* This file provides the implementation of the native interface functions for ANT
+*
+*
+\*******************************************************************************/
+
+#include "android_runtime/AndroidRuntime.h"
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+
+static JNIEnv *g_jEnv = NULL;
+static JavaVM *g_jVM = NULL;
+static jclass g_sJClazz;
+static jmethodID g_sMethodId_nativeCb_AntRxMessage;
+static jmethodID g_sMethodId_nativeCb_AntStateChange;
+
+extern "C"
+{
+ #include "ant_native.h"
+ #include "ant_log.h"
+ #undef LOG_TAG
+ #define LOG_TAG "JAntNative"
+
+ void nativeJAnt_RxCallback(ANT_U8 ucLen, ANT_U8* pucData);
+ void nativeJAnt_StateCallback(ANTRadioEnabledStatus uiNewState);
+}
+
+static jint nativeJAnt_Create(JNIEnv *env, jobject obj)
+{
+ ANTStatus antStatus = ANT_STATUS_FAILED;
+ (void)env; //unused warning
+ (void)obj; //unused warning
+
+ ANT_FUNC_START();
+
+ antStatus = ant_init();
+ if (antStatus)
+ {
+ ANT_DEBUG_D("failed to init ANT stack");
+ goto CLEANUP;
+ }
+
+ antStatus = set_ant_rx_callback(nativeJAnt_RxCallback);
+ if (antStatus)
+ {
+ ANT_DEBUG_D("failed to set ANT rx callback");
+ goto CLEANUP;
+ }
+
+ antStatus = set_ant_state_callback(nativeJAnt_StateCallback);
+ if (antStatus)
+ {
+ ANT_DEBUG_D("failed to set ANT state callback");
+ goto CLEANUP;
+ }
+
+CLEANUP:
+ ANT_FUNC_END();
+ return antStatus;
+}
+
+static jint nativeJAnt_Destroy(JNIEnv *env, jobject obj)
+{
+ (void)env; //unused warning
+ (void)obj; //unused warning
+ ANTStatus status;
+ ANT_FUNC_START();
+
+ ANT_DEBUG_D("nativeJAnt_Destroy(): calling ant_deinit");
+ status = ant_deinit();
+ if (status)
+ {
+ ANT_DEBUG_D("failed to deinit ANT stack returned %d",(int)status);
+ return status;
+ }
+ else
+ {
+ ANT_DEBUG_D("deinit ANT stack Success");
+ }
+
+ ANT_FUNC_END();
+ return status;
+}
+
+static jint nativeJAnt_Enable(JNIEnv *env, jobject obj)
+{
+ (void)env; //unused warning
+ (void)obj; //unused warning
+ ANT_FUNC_START();
+
+ ANTStatus status = ant_enable_radio();
+
+ ANT_FUNC_END();
+ return status;
+}
+
+static jint nativeJAnt_Disable(JNIEnv *env, jobject obj)
+{
+ (void)env; //unused warning
+ (void)obj; //unused warning
+ ANT_FUNC_START();
+
+ ANTStatus status = ant_disable_radio();
+
+ ANT_FUNC_END();
+ return status;
+}
+
+static jint nativeJAnt_GetRadioEnabledStatus(JNIEnv *env, jobject obj)
+{
+ (void)env; //unused warning
+ (void)obj; //unused warning
+ ANT_FUNC_START();
+
+ jint status = ant_radio_enabled_status();
+
+ ANT_FUNC_END();
+ return status;
+}
+
+static jint nativeJAnt_TxMessage(JNIEnv *env, jobject obj, jbyteArray msg)
+{
+ (void)obj; //unused warning
+ ANT_FUNC_START();
+
+ if (msg == NULL)
+ {
+ if (jniThrowException(env, "java/lang/NullPointerException", NULL))
+ {
+ ANT_ERROR("Unable to throw NullPointerException");
+ }
+ return -1;
+ }
+
+ jbyte* msgBytes = env->GetByteArrayElements(msg, NULL);
+ jint msgLength = env->GetArrayLength(msg);
+
+ ANTStatus status = ant_tx_message((ANT_U8) msgLength, (ANT_U8 *)msgBytes);
+ ANT_DEBUG_D("nativeJAnt_TxMessage: ant_tx_message() returned %d", (int)status);
+
+ env->ReleaseByteArrayElements(msg, msgBytes, JNI_ABORT);
+
+ ANT_FUNC_END();
+ return status;
+}
+
+static jint nativeJAnt_HardReset(JNIEnv *env, jobject obj)
+{
+ (void)env; //unused warning
+ (void)obj; //unused warning
+ ANT_FUNC_START();
+
+ ANTStatus status = ant_radio_hard_reset();
+
+ ANT_FUNC_END();
+ return status;
+}
+
+extern "C"
+{
+
+ /**********************************************************************
+ * Callback registration
+ ***********************************************************************/
+ void nativeJAnt_RxCallback(ANT_U8 ucLen, ANT_U8* pucData)
+ {
+ JNIEnv* env = NULL;
+ jbyteArray jAntRxMsg = NULL;
+ ANT_FUNC_START();
+
+ ANT_DEBUG_D( "got message %d bytes", ucLen);
+
+ g_jVM->AttachCurrentThread((&env), NULL);
+
+ if (env == NULL)
+ {
+ ANT_DEBUG_D("nativeJAnt_RxCallback: Entered, env is null");
+ return; // log error? cleanup?
+ }
+ else
+ {
+ ANT_DEBUG_D("nativeJAnt_RxCallback: jEnv %p", env);
+ }
+
+ jAntRxMsg = env->NewByteArray(ucLen);
+
+ if (jAntRxMsg == NULL)
+ {
+ ANT_ERROR("nativeJAnt_RxCallback: Failed creating java byte[]");
+ goto CLEANUP;
+ }
+
+ env->SetByteArrayRegion(jAntRxMsg,0,ucLen,(jbyte*)pucData);
+
+ if (env->ExceptionOccurred())
+ {
+ ANT_ERROR("nativeJAnt_RxCallback: ExceptionOccurred during byte[] copy");
+ goto CLEANUP;
+ }
+ ANT_DEBUG_V("nativeJAnt_RxCallback: Calling java rx callback");
+ env->CallStaticVoidMethod(g_sJClazz, g_sMethodId_nativeCb_AntRxMessage, jAntRxMsg);
+ ANT_DEBUG_V("nativeJAnt_RxCallback: Called java rx callback");
+
+ if (env->ExceptionOccurred())
+ {
+ ANT_ERROR("nativeJAnt_RxCallback: Calling Java nativeCb_AntRxMessage failed");
+ goto CLEANUP;
+ }
+
+ //Delete the local references
+ if (jAntRxMsg != NULL)
+ {
+ env->DeleteLocalRef(jAntRxMsg);
+ }
+
+ ANT_DEBUG_D("nativeJAnt_RxCallback: Exiting, Calling DetachCurrentThread at the END");
+
+ g_jVM->DetachCurrentThread();
+
+ ANT_FUNC_END();
+ return;
+
+ CLEANUP:
+ ANT_ERROR("nativeJAnt_RxCallback: Exiting due to failure");
+ if (jAntRxMsg != NULL)
+ {
+ env->DeleteLocalRef(jAntRxMsg);
+ }
+
+ if (env->ExceptionOccurred())
+ {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ g_jVM->DetachCurrentThread();
+
+ return;
+ }
+
+ void nativeJAnt_StateCallback(ANTRadioEnabledStatus uiNewState)
+ {
+ JNIEnv* env = NULL;
+ jint jNewState = uiNewState;
+ ANT_BOOL iShouldDetach = ANT_FALSE;
+ ANT_FUNC_START();
+
+ g_jVM->GetEnv((void**) &env, JNI_VERSION_1_4);
+ if (env == NULL)
+ {
+ ANT_DEBUG_D("nativeJAnt_StateCallback: called from rx thread, attaching to VM");
+ g_jVM->AttachCurrentThread((&env), NULL);
+ if (env == NULL)
+ {
+ ANT_DEBUG_E("nativeJAnt_StateCallback: failed to attach rx thread to VM");
+ return;
+ }
+ iShouldDetach = ANT_TRUE;
+ }
+ else
+ {
+ ANT_DEBUG_D("nativeJAnt_StateCallback: called from java enable/disable"
+ ", already attached, don't detach");
+ }
+
+ ANT_DEBUG_V("nativeJAnt_StateCallback: Calling java state callback");
+ env->CallStaticVoidMethod(g_sJClazz, g_sMethodId_nativeCb_AntStateChange, jNewState);
+ ANT_DEBUG_V("nativeJAnt_StateCallback: Called java state callback");
+
+ if (env->ExceptionOccurred())
+ {
+ ANT_ERROR("nativeJAnt_StateCallback: Calling Java nativeCb_AntStateChange failed");
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ if (iShouldDetach)
+ {
+ ANT_DEBUG_D("nativeJAnt_StateCallback: env was attached, detaching");
+ g_jVM->DetachCurrentThread();
+ }
+
+ ANT_FUNC_END();
+ return;
+ }
+}
+
+static JNINativeMethod g_sMethods[] =
+{
+ /* name, signature, funcPtr */
+ {"nativeJAnt_Create", "()I", (void*)nativeJAnt_Create},
+ {"nativeJAnt_Destroy", "()I", (void*)nativeJAnt_Destroy},
+ {"nativeJAnt_Enable", "()I", (void*)nativeJAnt_Enable},
+ {"nativeJAnt_Disable", "()I", (void*)nativeJAnt_Disable},
+ {"nativeJAnt_GetRadioEnabledStatus", "()I", (void*)nativeJAnt_GetRadioEnabledStatus},
+ {"nativeJAnt_TxMessage","([B)I", (void*)nativeJAnt_TxMessage},
+ {"nativeJAnt_HardReset", "()I", (void *)nativeJAnt_HardReset}
+};
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+ ANT_FUNC_START();
+ (void)reserved; //unused warning
+
+ g_jVM = vm;
+ if (g_jVM->GetEnv((void**) &g_jEnv, JNI_VERSION_1_4) != JNI_OK) {
+ ANT_ERROR("GetEnv failed");
+ return -1;
+ }
+ if (NULL == g_jEnv) {
+ ANT_ERROR("env is null");
+ return -1;
+ }
+
+ g_sJClazz = g_jEnv->FindClass("com/dsi/ant/core/JAntJava");
+ if (NULL == g_sJClazz) {
+ ANT_ERROR("could not find class \"com/dsi/ant/core/JAntJava\"");
+ return -1;
+ }
+
+ /* Save class information in global reference to prevent class unloading */
+ g_sJClazz = (jclass)g_jEnv->NewGlobalRef(g_sJClazz);
+
+ if (g_jEnv->RegisterNatives(g_sJClazz, g_sMethods, NELEM(g_sMethods)) != JNI_OK) {
+ ANT_ERROR("failed to register methods");
+ return -1;
+ }
+
+ g_sMethodId_nativeCb_AntRxMessage = g_jEnv->GetStaticMethodID(g_sJClazz,
+ "nativeCb_AntRxMessage", "([B)V");
+ if (NULL == g_sMethodId_nativeCb_AntRxMessage) {
+ ANT_ERROR("VerifyMethodId: Failed getting method id of \"void nativeCb_AntRxMessage(byte[])\"");
+ return -1;
+ }
+
+ g_sMethodId_nativeCb_AntStateChange = g_jEnv->GetStaticMethodID(g_sJClazz,
+ "nativeCb_AntStateChange", "(I)V");
+ if (NULL == g_sMethodId_nativeCb_AntStateChange) {
+ ANT_ERROR("VerifyMethodId: Failed getting method id of \"void nativeCb_AntStateChange(int)\"");
+ return -1;
+ }
+
+ ANT_FUNC_END();
+ return JNI_VERSION_1_4;
+}
+