#include <jni.h>
|
#include <string>
|
#include <mutex>
|
#include <unistd.h>
|
#include <cstdlib>
|
#include <map>
|
#include "common/serial_port.h"
|
#include "jni_log.h"
|
#include "common/net.h"
|
#include "common/apptimer.h"
|
#include "rtk_platform/parse_net.h"
|
#include "native-lib.h"
|
#include "test_common/Geometry.h"
|
#include "rtk_platform/platform.h"
|
#include "rtk_module/rtk.h"
|
#include "mcu/mcu_if.h"
|
#include "driver_test.h"
|
#include "master/comm_if.h"
|
#include "rtk_module/virtual_rtk.h"
|
#include "defs.h"
|
#include "mcu/ada.h"
|
#include "mcu/ahp.h"
|
|
#define DEBUG(fmt, args...) LOGD("<native-lib> <%s>: " fmt, __func__, ##args)
|
|
#define LIBENC_ARRAY_ELEMS(a) (sizeof(a) / sizeof(a[0]))
|
|
static JavaVM *sg_jvm = NULL;
|
static jobject sg_obj = NULL;
|
static JNIEnv *jenv;
|
|
|
const char *RTK_PLATFORM_IP = "47.93.80.84";
|
const int RTK_PLATFORM_PORT = 12125;
|
const uint8_t phone[] = {0x20,0x19,0x10,0x15,0x00,0x00,0x00,0x01};
|
|
const char *VIRTUAL_RTK_IP = "192.168.16.212";
|
const int VIRTUAL_RTK_PORT = 9002;
|
|
static std::mutex tts_mutex;
|
|
static std::map<int, void (*)(int)> TTSCallBack;
|
|
int DESEncrypt(const uint8_t *key, int key_length,
|
const uint8_t *plaintext, int plaintext_length,
|
uint8_t **ciphertext)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
int ciphertext_length = 0;
|
*ciphertext = NULL;
|
|
LOGD("JNI_DESEncrypt");
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return 0;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "javaDESEncrypt", "([B[B)[B");
|
|
jbyteArray jni_key = env->NewByteArray(key_length);
|
jbyteArray jni_plaintext = env->NewByteArray(plaintext_length);
|
|
env->SetByteArrayRegion(jni_key, 0, key_length, (jbyte *) key);
|
env->SetByteArrayRegion(jni_plaintext, 0, plaintext_length, (jbyte *) plaintext);
|
|
jbyteArray jni_ciphertext = (jbyteArray) env->CallObjectMethod(sg_obj, fun, jni_plaintext, jni_key);
|
if (jni_ciphertext != NULL) {
|
ciphertext_length = env->GetArrayLength(jni_ciphertext);
|
uint8_t *buffer = (uint8_t *)malloc(ciphertext_length);
|
env->GetByteArrayRegion(jni_ciphertext, 0, ciphertext_length, (jbyte *) buffer);
|
*ciphertext = buffer;
|
}
|
|
env->DeleteLocalRef(jni_key);
|
env->DeleteLocalRef(jni_plaintext);
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
return ciphertext_length;
|
}
|
|
void TextOsd(int type, const char *text)
|
{
|
/* JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "TextOsd", "(ILjava/lang/String;)V");
|
|
std::string cstext = text;
|
env->CallVoidMethod(sg_obj, fun, type, env->NewStringUTF(cstext.c_str()));
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}*/
|
}
|
|
void DrawScreen(const Polygon *map, const Polygon *car)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "DrawMap", "([[D[[D)V");
|
|
jclass doubleArrCls = env->FindClass("[D");
|
jobjectArray retmap = env->NewObjectArray(map->num, doubleArrCls, NULL);
|
jobjectArray retcar = env->NewObjectArray(car->num, doubleArrCls, NULL);
|
|
for (int i = 0; i < map->num; ++i) {
|
jdoubleArray doubleArr = env->NewDoubleArray(2);
|
jdouble tmp[2] = {map->point[i].X, 0 - map->point[i].Y};
|
|
env->SetDoubleArrayRegion(doubleArr, 0, 2, tmp);
|
env->SetObjectArrayElement(retmap, i, doubleArr);
|
env->DeleteLocalRef(doubleArr);
|
}
|
|
for (int i = 0; i < car->num; ++i) {
|
jdoubleArray doubleArr = env->NewDoubleArray(2);
|
jdouble tmp[2] = {car->point[i].X, 0 - car->point[i].Y};
|
|
env->SetDoubleArrayRegion(doubleArr, 0, 2, tmp);
|
env->SetObjectArrayElement(retcar, i, doubleArr);
|
env->DeleteLocalRef(doubleArr);
|
}
|
|
env->CallVoidMethod(sg_obj, fun, retmap, retcar);
|
env->DeleteLocalRef(retmap);
|
env->DeleteLocalRef(retcar);
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
}
|
|
int SendMsgToMainProc(int cmd, const char *value)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
int ret;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return -3;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "SendMsgToMainProc", "(ILjava/lang/String;)I");
|
|
ret = env->CallIntMethod(sg_obj, fun, cmd, value != NULL ? env->NewStringUTF(value) : NULL);
|
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
|
return ret;
|
}
|
|
static int GetTtsSeq(void)
|
{
|
static int seq = 0;
|
|
lock_guard<std::mutex> lock(tts_mutex);
|
seq++;
|
return seq;
|
}
|
|
int PlayTTS(const char *string, void (*callback)(int))
|
{
|
DEBUG("PlayTTS: %s", string);
|
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return -1;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "TextSpeak", "(Ljava/lang/String;I)V");
|
|
int id = GetTtsSeq();
|
|
env->CallVoidMethod(sg_obj, fun, env->NewStringUTF(string), id);
|
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
|
TTSCallBack.insert(pair<int, void (*)(int)>(id, callback));
|
|
return id;
|
}
|
|
int PlayTTS(std::string &tts, void (*callback)(int))
|
{
|
return PlayTTS(tts.c_str(), callback);
|
}
|
|
void PlayRing(void)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "PlayBreakRing", "()V");
|
|
env->CallVoidMethod(sg_obj, fun);
|
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
}
|
|
void GetUpgrade(int province, int city)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "GetUpgrade", "(II)V");
|
|
env->CallVoidMethod(sg_obj, fun, province, city);
|
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
}
|
|
|
void SendToBluetooth(const uint8_t *data, int length)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "WriteBluetooth", "([B)V");
|
|
jbyteArray array = env->NewByteArray(length);
|
|
env->SetByteArrayRegion(array, 0, length, (jbyte *) data);
|
|
env->CallVoidMethod(sg_obj, fun, array);
|
|
env->DeleteLocalRef(array);
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
}
|
|
void ConnectToBluetooth(const char *addr, const char *pin)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "ConnectBluetooth", "(Ljava/lang/String;Ljava/lang/String;)V");
|
|
env->CallVoidMethod(sg_obj, fun, env->NewStringUTF(addr), (pin == NULL) ? NULL : env->NewStringUTF(pin));
|
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
}
|
|
void DisconnectBluetooth(void)
|
{
|
JNIEnv *env;
|
bool ready_in_java_env = false;
|
|
if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
// Attach主线程
|
if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
|
LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
|
return;
|
}
|
} else {
|
ready_in_java_env = true;
|
}
|
|
jclass cls = env->GetObjectClass(sg_obj);
|
jmethodID fun = env->GetMethodID(cls, "DisconnectBluetooth", "()V");
|
|
env->CallVoidMethod(sg_obj, fun);
|
|
env->DeleteLocalRef(cls);
|
|
if (!ready_in_java_env) {
|
//Detach主线程
|
if (sg_jvm->DetachCurrentThread() != JNI_OK) {
|
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
|
}
|
}
|
}
|
|
static void startNative(JNIEnv *env, jobject thiz, jboolean ayDevice) {
|
// TODO: implement startNative()
|
// 保存全局JVM以便在子线程中使用
|
DEBUG("启动Native 逻辑cpu数量 = %d", std::thread::hardware_concurrency());
|
// 不能直接赋值(g_obj = ojb)
|
sg_obj = env->NewGlobalRef(thiz);
|
|
srand(time(NULL));
|
|
AppTimer_init();
|
///////////////ConfigMCU(ayDevice);
|
InitAda();
|
InitAhp();
|
DriverTestInit();
|
|
MA_Init();
|
InitPlatform(ayDevice, phone, RTK_PLATFORM_IP, RTK_PLATFORM_PORT);
|
|
InitVirtualDevice(VIRTUAL_RTK_IP, VIRTUAL_RTK_PORT);
|
|
// MA_NdkStart();
|
}
|
|
static void MainProcMsgEntry(JNIEnv *env, jobject thiz, jint cmd,
|
jstring value) {
|
// TODO: implement MainProcMsgEntry()
|
union {
|
int a;
|
uint8_t b[sizeof(int)];
|
} c;
|
|
c.a = cmd;
|
|
if (value != NULL) {
|
const char *str = env->GetStringUTFChars(value, 0);
|
|
uint8_t *data = new uint8_t[4 + strlen(str) + 1];
|
|
data[0] = c.b[0];
|
data[1] = c.b[1];
|
data[2] = c.b[2];
|
data[3] = c.b[3];
|
|
strcpy((char *)data + 4, str);
|
// MA_MainProcMsgEntry(cmd, str);
|
PlatformStatusChanged(MASTER_COMM_EVT, data, 4 + strlen(str) + 1);
|
env->ReleaseStringUTFChars(value, str);
|
|
delete []data;
|
} else {
|
//MA_MainProcMsgEntry(cmd, NULL);
|
PlatformStatusChanged(MASTER_COMM_EVT, c.b, sizeof(int));
|
}
|
}
|
|
void MainProcBinMsgEntry(JNIEnv *env, jobject thiz, jint cmd,
|
jbyteArray data, jint length) {
|
// TODO: implement MainProcBinMsgEntry()
|
jbyte *c_dat = env->GetByteArrayElements(data, NULL);
|
int len = env->GetArrayLength(data);
|
|
MA_MainProcBinMsgEntry(cmd, (uint8_t *)c_dat, len);
|
|
env->ReleaseByteArrayElements(data, c_dat, NULL);
|
}
|
|
void TextSpeakEnd(JNIEnv *env, jobject thiz, jint id) {
|
// TODO: implement TextSpeakEnd()
|
auto it = TTSCallBack.find(id);
|
|
if (it != TTSCallBack.end()) {
|
if (it->second != NULL) {
|
tts_back_t tb;
|
|
tb.seq = id;
|
tb.callback = (void (*)(int)) it->second;
|
PlatformStatusChanged(PLAY_TTS_DONE_EVT, (uint8_t *)&tb, sizeof(tb));
|
}
|
TTSCallBack.erase(it);
|
}
|
}
|
|
void UpgradeMcu(JNIEnv *env, jobject thiz, jstring vercode,
|
jbyteArray rom) {
|
// TODO: implement UpgradeMcu()
|
if (vercode != NULL && rom != NULL) {
|
const char *str = env->GetStringUTFChars(vercode, 0);
|
jbyte *c_dat = env->GetByteArrayElements(rom, NULL);
|
int len = env->GetArrayLength(rom);
|
|
LoadDefaultMcuRom(str, (uint8_t *)c_dat, len);
|
|
env->ReleaseStringUTFChars(vercode, str);
|
env->ReleaseByteArrayElements(rom, c_dat, NULL);
|
}
|
}
|
|
void BluetoothDataComeIn(JNIEnv *env, jobject thiz,
|
jbyteArray data, jint length) {
|
// TODO: implement BluetoothDataComeIn()
|
jbyte *c_dat = env->GetByteArrayElements(data, NULL);
|
|
PlatformStatusChanged(BLUETOOTH_DATA_EVT, (uint8_t *)c_dat, length);
|
|
env->ReleaseByteArrayElements(data, c_dat, NULL);
|
}
|
|
|
void BluetoothStatusChange(JNIEnv *env, jobject thiz,
|
jint status) {
|
// TODO: implement BluetoothStatusChange()
|
uint8_t sta = status;
|
|
PlatformStatusChanged(BLUETOOTH_STATUS_EVT, &sta, 1);
|
}
|
|
void BluetoothConnected(JNIEnv *env, jobject thiz, jstring name,
|
jstring addr) {
|
// TODO: implement BluetoothConnected()
|
if (name != NULL && addr != NULL) {
|
const char *strname = env->GetStringUTFChars(name, 0);
|
const char *straddr = env->GetStringUTFChars(addr, 0);
|
|
uint8_t data[128];
|
strcpy((char *)data, strname);
|
strcpy((char *)data + 64, straddr);
|
|
env->ReleaseStringUTFChars(name, strname);
|
env->ReleaseStringUTFChars(addr, straddr);
|
|
PlatformStatusChanged(BLUETOOTH_STATUS_EVT, data, 128);
|
} else if (addr != NULL) {
|
const char *straddr = env->GetStringUTFChars(addr, 0);
|
|
uint8_t data[64];
|
strcpy((char *)data, straddr);
|
|
env->ReleaseStringUTFChars(addr, straddr);
|
|
PlatformStatusChanged(BLUETOOTH_STATUS_EVT, data, 64);
|
} else {
|
uint8_t sta = 3;
|
PlatformStatusChanged(BLUETOOTH_STATUS_EVT, &sta, 1);
|
}
|
}
|
|
static JNINativeMethod methods[] = {
|
{"startNative", "(Z)V", reinterpret_cast<void *>(startNative)},
|
{"MainProcMsgEntry", "(ILjava/lang/String;)V", reinterpret_cast<void *>(MainProcMsgEntry)},
|
{"MainProcBinMsgEntry", "(I[BI)V", reinterpret_cast<void *>(MainProcBinMsgEntry)},
|
{"UpgradeMcu", "(Ljava/lang/String;[B)V", reinterpret_cast<void *>(UpgradeMcu)},
|
{"TextSpeakEnd", "(I)V", reinterpret_cast<void *>(TextSpeakEnd)},
|
{"BluetoothConnected", "(Ljava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void *>(BluetoothConnected)},
|
{"BluetoothStatusChange", "(I)V", reinterpret_cast<void *>(BluetoothStatusChange)},
|
{"BluetoothDataComeIn", "([BI)V", reinterpret_cast<void *>(BluetoothDataComeIn)}
|
};
|
|
jint JNI_OnLoad(JavaVM *vm, void *reserved)
|
{
|
sg_jvm = vm;
|
|
if (sg_jvm->GetEnv(reinterpret_cast<void **> (&jenv), JNI_VERSION_1_6) != JNI_OK) {
|
DEBUG("Env not got");
|
return JNI_ERR;
|
}
|
|
jclass clz = jenv->FindClass("com/anyun/exam/lib/RemoteService");
|
if (clz == NULL) {
|
DEBUG("目标类未找到");
|
return JNI_ERR;
|
}
|
|
if (jenv->RegisterNatives(clz, methods, LIBENC_ARRAY_ELEMS(methods))) {
|
DEBUG("methods not registered");
|
return JNI_ERR;
|
}
|
|
DEBUG("JNI_OnLoad");
|
|
return JNI_VERSION_1_6;
|
}
|
|
void JNI_OnUnload(JavaVM* vm, void* reserved)
|
{
|
JNIEnv* env;
|
|
if (vm->GetEnv(reinterpret_cast<void **> (&env), JNI_VERSION_1_6) != JNI_OK) {
|
DEBUG("Env not got");
|
return;
|
}
|
|
jclass clz = env->FindClass("com/anyun/exam/lib/RemoteService");
|
if (clz == NULL) {
|
DEBUG("目标类未找到");
|
return;
|
}
|
|
env->UnregisterNatives(clz);
|
|
DEBUG("JNI_OnUnload");
|
}
|