Merge pull request #3593 from Sonicadvance1/Android_Mayflash_adapter

[Android] Implement support for real Wiimotes with the DolphinBar
This commit is contained in:
Ryan Houdek
2016-02-07 15:51:33 -05:00
9 changed files with 351 additions and 0 deletions

View File

@ -256,6 +256,8 @@ elseif(UNIX)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND BLUEZ_FOUND)
set(SRCS ${SRCS} HW/WiimoteReal/IONix.cpp)
set(LIBS ${LIBS} bluetooth)
elseif(ANDROID)
set(SRCS ${SRCS} HW/WiimoteReal/IOAndroid.cpp)
else()
set(SRCS ${SRCS} HW/WiimoteReal/IODummy.cpp)
endif()

View File

@ -0,0 +1,165 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <jni.h>
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/Flag.h"
#include "Common/StringUtil.h"
#include "Common/Thread.h"
#include "Common/Timer.h"
#include "Common/Logging/Log.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h"
// Global java_vm class
extern JavaVM* g_java_vm;
namespace WiimoteReal
{
// Java classes
static jclass s_adapter_class;
class WiimoteAndroid final : public Wiimote
{
public:
WiimoteAndroid(int index);
~WiimoteAndroid() override;
protected:
bool ConnectInternal() override;
void DisconnectInternal() override;
bool IsConnected() const override;
void IOWakeup() {}
int IORead(u8* buf) override;
int IOWrite(u8 const* buf, size_t len) override;
private:
int m_mayflash_index;
bool is_connected = true;
JNIEnv* m_env;
jmethodID m_input_func;
jmethodID m_output_func;
jbyteArray m_java_wiimote_payload;
};
WiimoteScanner::WiimoteScanner()
{}
WiimoteScanner::~WiimoteScanner()
{}
void WiimoteScanner::Update()
{}
void WiimoteScanner::FindWiimotes(std::vector<Wiimote*>& found_wiimotes, Wiimote*& found_board)
{
found_wiimotes.clear();
found_board = nullptr;
NOTICE_LOG(WIIMOTE, "Finding Wiimotes");
JNIEnv* env;
int get_env_status = g_java_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
if (get_env_status == JNI_EDETACHED)
g_java_vm->AttachCurrentThread(&env, nullptr);
jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z");
jmethodID queryadapter_func = env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z");
if (env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func) &&
env->CallStaticBooleanMethod(s_adapter_class, openadapter_func))
{
for (int i = 0; i < MAX_WIIMOTES; ++i)
found_wiimotes.emplace_back(new WiimoteAndroid(i));
}
if (get_env_status == JNI_EDETACHED)
g_java_vm->DetachCurrentThread();
}
bool WiimoteScanner::IsReady() const
{
return true;
}
WiimoteAndroid::WiimoteAndroid(int index)
: Wiimote(), m_mayflash_index(index)
{
}
WiimoteAndroid::~WiimoteAndroid()
{
Shutdown();
}
// Connect to a Wiimote with a known address.
bool WiimoteAndroid::ConnectInternal()
{
g_java_vm->AttachCurrentThread(&m_env, nullptr);
jfieldID payload_field = m_env->GetStaticFieldID(s_adapter_class, "wiimote_payload", "[[B");
jobjectArray payload_object = reinterpret_cast<jobjectArray>(m_env->GetStaticObjectField(s_adapter_class, payload_field));
m_java_wiimote_payload = (jbyteArray)m_env->GetObjectArrayElement(payload_object, m_mayflash_index);
// Get function pointers
m_input_func = m_env->GetStaticMethodID(s_adapter_class, "Input", "(I)I");
m_output_func = m_env->GetStaticMethodID(s_adapter_class, "Output", "(I[BI)I");
is_connected = true;
return true;
}
void WiimoteAndroid::DisconnectInternal()
{
g_java_vm->DetachCurrentThread();
}
bool WiimoteAndroid::IsConnected() const
{
return is_connected;
}
// positive = read packet
// negative = didn't read packet
// zero = error
int WiimoteAndroid::IORead(u8* buf)
{
int read_size = m_env->CallStaticIntMethod(s_adapter_class, m_input_func, m_mayflash_index);
jbyte* java_data = m_env->GetByteArrayElements(m_java_wiimote_payload, nullptr);
memcpy(buf + 1, java_data, std::min(MAX_PAYLOAD - 1, read_size));
buf[0] = 0xA1;
m_env->ReleaseByteArrayElements(m_java_wiimote_payload, java_data, 0);
return read_size <= 0 ? read_size : read_size + 1;
}
int WiimoteAndroid::IOWrite(u8 const* buf, size_t len)
{
jbyteArray output_array = m_env->NewByteArray(len);
jbyte* output = m_env->GetByteArrayElements(output_array, nullptr);
memcpy(output, buf, len);
m_env->ReleaseByteArrayElements(output_array, output, 0);
int written = m_env->CallStaticIntMethod(s_adapter_class, m_output_func, m_mayflash_index, output_array, len);
m_env->DeleteLocalRef(output_array);
return written;
}
void InitAdapterClass()
{
JNIEnv* env;
g_java_vm->AttachCurrentThread(&env, nullptr);
jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter");
s_adapter_class = reinterpret_cast<jclass>(env->NewGlobalRef(adapter_class));
}
}

View File

@ -161,4 +161,8 @@ void ChangeWiimoteSource(unsigned int index, int source);
bool IsValidBluetoothName(const std::string& name);
bool IsBalanceBoardName(const std::string& name);
#ifdef ANDROID
void InitAdapterClass();
#endif
} // WiimoteReal