1 // Copyright 2016 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include <jni.h>
6 
7 #include "Common/CommonTypes.h"
8 #include "Common/Event.h"
9 #include "Common/Flag.h"
10 #include "Common/Logging/Log.h"
11 #include "Common/StringUtil.h"
12 #include "Common/Thread.h"
13 #include "Common/Timer.h"
14 
15 #include "Core/HW/WiimoteReal/IOAndroid.h"
16 
17 #include "jni/AndroidCommon/IDCache.h"
18 
19 namespace WiimoteReal
20 {
21 // Java classes
22 static jclass s_adapter_class;
23 
FindWiimotes(std::vector<Wiimote * > & found_wiimotes,Wiimote * & found_board)24 void WiimoteScannerAndroid::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
25                                          Wiimote*& found_board)
26 {
27   found_wiimotes.clear();
28   found_board = nullptr;
29 
30   NOTICE_LOG(WIIMOTE, "Finding Wiimotes");
31 
32   JNIEnv* env = IDCache::GetEnvForThread();
33 
34   jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z");
35   jmethodID queryadapter_func = env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z");
36 
37   if (env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func) &&
38       env->CallStaticBooleanMethod(s_adapter_class, openadapter_func))
39   {
40     for (int i = 0; i < MAX_WIIMOTES; ++i)
41       found_wiimotes.emplace_back(new WiimoteAndroid(i));
42   }
43 }
44 
WiimoteAndroid(int index)45 WiimoteAndroid::WiimoteAndroid(int index) : Wiimote(), m_mayflash_index(index)
46 {
47 }
48 
~WiimoteAndroid()49 WiimoteAndroid::~WiimoteAndroid()
50 {
51   Shutdown();
52 }
53 
54 // Connect to a Wiimote with a known address.
ConnectInternal()55 bool WiimoteAndroid::ConnectInternal()
56 {
57   m_env = IDCache::GetEnvForThread();
58 
59   jfieldID payload_field = m_env->GetStaticFieldID(s_adapter_class, "wiimote_payload", "[[B");
60   jobjectArray payload_object =
61       reinterpret_cast<jobjectArray>(m_env->GetStaticObjectField(s_adapter_class, payload_field));
62   m_java_wiimote_payload =
63       (jbyteArray)m_env->GetObjectArrayElement(payload_object, m_mayflash_index);
64 
65   // Get function pointers
66   m_input_func = m_env->GetStaticMethodID(s_adapter_class, "Input", "(I)I");
67   m_output_func = m_env->GetStaticMethodID(s_adapter_class, "Output", "(I[BI)I");
68 
69   is_connected = true;
70 
71   return true;
72 }
73 
DisconnectInternal()74 void WiimoteAndroid::DisconnectInternal()
75 {
76 }
77 
IsConnected() const78 bool WiimoteAndroid::IsConnected() const
79 {
80   return is_connected;
81 }
82 
83 // positive = read packet
84 // negative = didn't read packet
85 // zero = error
IORead(u8 * buf)86 int WiimoteAndroid::IORead(u8* buf)
87 {
88   int read_size = m_env->CallStaticIntMethod(s_adapter_class, m_input_func, m_mayflash_index);
89   if (read_size > 0)
90   {
91     jbyte* java_data = m_env->GetByteArrayElements(m_java_wiimote_payload, nullptr);
92     memcpy(buf + 1, java_data, std::min(MAX_PAYLOAD - 1, read_size));
93     buf[0] = 0xA1;
94     m_env->ReleaseByteArrayElements(m_java_wiimote_payload, java_data, 0);
95   }
96   return read_size <= 0 ? read_size : read_size + 1;
97 }
98 
IOWrite(u8 const * buf,size_t len)99 int WiimoteAndroid::IOWrite(u8 const* buf, size_t len)
100 {
101   jbyteArray output_array = m_env->NewByteArray(len);
102   jbyte* output = m_env->GetByteArrayElements(output_array, nullptr);
103   memcpy(output, buf, len);
104   m_env->ReleaseByteArrayElements(output_array, output, 0);
105   int written = m_env->CallStaticIntMethod(s_adapter_class, m_output_func, m_mayflash_index,
106                                            output_array, len);
107   m_env->DeleteLocalRef(output_array);
108   return written;
109 }
110 
InitAdapterClass()111 void InitAdapterClass()
112 {
113   JNIEnv* env = IDCache::GetEnvForThread();
114   jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter");
115   s_adapter_class = reinterpret_cast<jclass>(env->NewGlobalRef(adapter_class));
116 }
117 }  // namespace WiimoteReal
118