mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #7674 from jordan-woyak/wiimote-emu-cleanup
WiimoteEmu: Major cleanups
This commit is contained in:
@@ -199,4 +199,56 @@ inline To BitCast(const From& source) noexcept
|
||||
std::memcpy(&storage, &source, sizeof(storage));
|
||||
return reinterpret_cast<To&>(storage);
|
||||
}
|
||||
|
||||
template <typename T, typename PtrType>
|
||||
class BitCastPtrType
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_trivially_copyable<PtrType>(),
|
||||
"BitCastPtr source type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"BitCastPtr destination type must be trivially copyable.");
|
||||
|
||||
explicit BitCastPtrType(PtrType* ptr) : m_ptr(ptr) {}
|
||||
|
||||
// Enable operator= only for pointers to non-const data
|
||||
template <typename S>
|
||||
inline typename std::enable_if<std::is_same<S, T>() && !std::is_const<PtrType>()>::type
|
||||
operator=(const S& source)
|
||||
{
|
||||
std::memcpy(m_ptr, &source, sizeof(source));
|
||||
}
|
||||
|
||||
inline operator T() const
|
||||
{
|
||||
T result;
|
||||
std::memcpy(&result, m_ptr, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
PtrType* m_ptr;
|
||||
};
|
||||
|
||||
// Provides an aliasing-safe alternative to reinterpret_cast'ing pointers to structs
|
||||
// Conversion constructor and operator= provided for a convenient syntax.
|
||||
// Usage: MyStruct s = BitCastPtr<MyStruct>(some_ptr);
|
||||
// BitCastPtr<MyStruct>(some_ptr) = s;
|
||||
template <typename T, typename PtrType>
|
||||
inline auto BitCastPtr(PtrType* ptr) noexcept -> BitCastPtrType<T, PtrType>
|
||||
{
|
||||
return BitCastPtrType<T, PtrType>{ptr};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SetBit(T& value, size_t bit_number, bool bit_value)
|
||||
{
|
||||
static_assert(std::is_unsigned<T>(), "SetBit is only sane on unsigned types.");
|
||||
|
||||
if (bit_value)
|
||||
value |= (T{1} << bit_number);
|
||||
else
|
||||
value &= ~(T{1} << bit_number);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -133,16 +133,22 @@ add_library(core
|
||||
HW/VideoInterface.cpp
|
||||
HW/WII_IPC.cpp
|
||||
HW/Wiimote.cpp
|
||||
HW/WiimoteCommon/DataReport.cpp
|
||||
HW/WiimoteEmu/WiimoteEmu.cpp
|
||||
HW/WiimoteEmu/Attachment/Classic.cpp
|
||||
HW/WiimoteEmu/Attachment/Attachment.cpp
|
||||
HW/WiimoteEmu/Attachment/Nunchuk.cpp
|
||||
HW/WiimoteEmu/Attachment/Drums.cpp
|
||||
HW/WiimoteEmu/Attachment/Guitar.cpp
|
||||
HW/WiimoteEmu/Attachment/Turntable.cpp
|
||||
HW/WiimoteEmu/Camera.cpp
|
||||
HW/WiimoteEmu/Dynamics.cpp
|
||||
HW/WiimoteEmu/EmuSubroutines.cpp
|
||||
HW/WiimoteEmu/Encryption.cpp
|
||||
HW/WiimoteEmu/ExtensionPort.cpp
|
||||
HW/WiimoteEmu/I2CBus.cpp
|
||||
HW/WiimoteEmu/MotionPlus.cpp
|
||||
HW/WiimoteEmu/Speaker.cpp
|
||||
HW/WiimoteEmu/Extension/Classic.cpp
|
||||
HW/WiimoteEmu/Extension/Extension.cpp
|
||||
HW/WiimoteEmu/Extension/Nunchuk.cpp
|
||||
HW/WiimoteEmu/Extension/Drums.cpp
|
||||
HW/WiimoteEmu/Extension/Guitar.cpp
|
||||
HW/WiimoteEmu/Extension/Turntable.cpp
|
||||
HW/WiimoteReal/WiimoteReal.cpp
|
||||
HW/WiiSave.cpp
|
||||
IOS/Device.cpp
|
||||
|
||||
@@ -171,14 +171,20 @@
|
||||
<ClCompile Include="HW\SystemTimers.cpp" />
|
||||
<ClCompile Include="HW\VideoInterface.cpp" />
|
||||
<ClCompile Include="HW\Wiimote.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Attachment.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Classic.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Drums.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Guitar.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Nunchuk.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Turntable.cpp" />
|
||||
<ClCompile Include="HW\WiimoteCommon\DataReport.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Camera.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Dynamics.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\EmuSubroutines.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Encryption.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\ExtensionPort.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Classic.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Drums.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Extension.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Guitar.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Nunchuk.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\I2CBus.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\MotionPlus.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Speaker.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\WiimoteEmu.cpp" />
|
||||
<ClCompile Include="HW\WiimoteReal\IOWin.cpp" />
|
||||
@@ -430,19 +436,25 @@
|
||||
<ClInclude Include="HW\SystemTimers.h" />
|
||||
<ClInclude Include="HW\VideoInterface.h" />
|
||||
<ClInclude Include="HW\Wiimote.h" />
|
||||
<ClInclude Include="HW\WiimoteCommon\DataReport.h" />
|
||||
<ClInclude Include="HW\WiimoteCommon\WiimoteConstants.h" />
|
||||
<ClInclude Include="HW\WiimoteCommon\WiimoteHid.h" />
|
||||
<ClInclude Include="HW\WiimoteCommon\WiimoteReport.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Attachment.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Classic.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Drums.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Guitar.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Nunchuk.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Turntable.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Camera.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Dynamics.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Encryption.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\ExtensionPort.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Classic.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Drums.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Extension.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Guitar.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Nunchuk.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Turntable.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\I2CBus.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\MatrixMath.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\MotionPlus.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Speaker.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\WiimoteEmu.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\WiimoteHid.h" />
|
||||
<ClInclude Include="HW\WiimoteReal\WiimoteReal.h" />
|
||||
<ClInclude Include="HW\WiimoteReal\WiimoteRealBase.h" />
|
||||
<ClInclude Include="HW\WiiSave.h" />
|
||||
|
||||
@@ -79,9 +79,6 @@
|
||||
<Filter Include="HW %28Flipper/Hollywood%29\Wiimote\Real">
|
||||
<UniqueIdentifier>{bc3e845a-3d01-4713-aa32-f27110838d0c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment">
|
||||
<UniqueIdentifier>{cdbd65da-541f-47d2-8fdc-e99e73e98e69}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="HW %28Flipper/Hollywood%29\EXI - Expansion Interface">
|
||||
<UniqueIdentifier>{d19f1218-0e28-4f24-a4b3-33fac750a899}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -163,9 +160,12 @@
|
||||
<Filter Include="PowerPC\SignatureDB">
|
||||
<UniqueIdentifier>{f0b52c84-49f4-470a-b037-edeea5634b9e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="HW %28Flipper/Hollywood%29\WiimoteCommon">
|
||||
<Filter Include="HW %28Flipper/Hollywood%29\Wiimote\Common">
|
||||
<UniqueIdentifier>{ee6645da-3ad9-4fe7-809f-e4646d0b0ca5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension">
|
||||
<UniqueIdentifier>{68c09d7e-4f5a-435d-a0d2-7eb7a74d7054}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BootManager.cpp" />
|
||||
@@ -516,33 +516,12 @@
|
||||
<ClCompile Include="HW\VideoInterface.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\VI - Video Interface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Attachment.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Classic.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Drums.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Guitar.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Nunchuk.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Attachment\Turntable.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\EmuSubroutines.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Encryption.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Speaker.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\WiimoteEmu.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
@@ -642,12 +621,6 @@
|
||||
<ClCompile Include="PowerPC\JitCommon\JitCache.cpp">
|
||||
<Filter>PowerPC\JitCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\FPURegCache.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\GPRRegCache.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\Jit_Branch.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
@@ -675,9 +648,6 @@
|
||||
<ClCompile Include="PowerPC\Jit64\JitAsm.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\JitRegCache.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\GCKeyboardEmu.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\GCKeyboard</Filter>
|
||||
</ClCompile>
|
||||
@@ -907,6 +877,48 @@
|
||||
<ClCompile Include="Config\WiimoteInputSettings.cpp">
|
||||
<Filter>Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\RegCache\FPURegCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\RegCache\GPRRegCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\RegCache\JitRegCache.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\I2CBus.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\MotionPlus.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Camera.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Speaker.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Dynamics.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Classic.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Drums.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Guitar.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Nunchuk.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Extension.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\ExtensionPort.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteCommon\DataReport.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BootManager.h" />
|
||||
@@ -1206,24 +1218,6 @@
|
||||
<ClInclude Include="HW\VideoInterface.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\VI - Video Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Attachment.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Classic.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Drums.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Guitar.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Nunchuk.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Attachment\Turntable.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Attachment</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Encryption.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
@@ -1233,9 +1227,6 @@
|
||||
<ClInclude Include="HW\WiimoteEmu\WiimoteEmu.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\WiimoteHid.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteReal\WiimoteReal.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Real</Filter>
|
||||
</ClInclude>
|
||||
@@ -1593,13 +1584,13 @@
|
||||
<Filter>IOS\Network\NCD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteCommon\WiimoteConstants.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\WiimoteCommon</Filter>
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteCommon\WiimoteHid.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\WiimoteCommon</Filter>
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteCommon\WiimoteReport.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\WiimoteCommon</Filter>
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\UISettings.h">
|
||||
<Filter>Config</Filter>
|
||||
@@ -1607,8 +1598,47 @@
|
||||
<ClInclude Include="Config\WiimoteInputSettings.h">
|
||||
<Filter>Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\I2CBus.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\MotionPlus.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Camera.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Speaker.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Dynamics.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Classic.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Drums.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Guitar.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Nunchuk.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Turntable.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Extension.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\ExtensionPort.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteCommon\DataReport.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -0,0 +1,431 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Core/HW/WiimoteCommon/DataReport.h"
|
||||
|
||||
namespace WiimoteCommon
|
||||
{
|
||||
bool DataReportManipulator::HasIR() const
|
||||
{
|
||||
return 0 != GetIRDataSize();
|
||||
}
|
||||
|
||||
bool DataReportManipulator::HasExt() const
|
||||
{
|
||||
return 0 != GetExtDataSize();
|
||||
}
|
||||
|
||||
u8* DataReportManipulator::GetDataPtr()
|
||||
{
|
||||
return data_ptr;
|
||||
}
|
||||
|
||||
const u8* DataReportManipulator::GetDataPtr() const
|
||||
{
|
||||
return data_ptr;
|
||||
}
|
||||
|
||||
struct IncludeCore : virtual DataReportManipulator
|
||||
{
|
||||
bool HasCore() const override { return true; }
|
||||
|
||||
void GetCoreData(CoreData* result) const override
|
||||
{
|
||||
*result = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
|
||||
// Remove accel LSBs.
|
||||
result->hex &= CoreData::BUTTON_MASK;
|
||||
}
|
||||
|
||||
void SetCoreData(const CoreData& new_core) override
|
||||
{
|
||||
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
|
||||
// Don't overwrite accel LSBs.
|
||||
core.hex &= ~CoreData::BUTTON_MASK;
|
||||
core.hex |= new_core.hex & CoreData::BUTTON_MASK;
|
||||
|
||||
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||
}
|
||||
};
|
||||
|
||||
struct NoCore : virtual DataReportManipulator
|
||||
{
|
||||
bool HasCore() const override { return false; }
|
||||
|
||||
void GetCoreData(CoreData*) const override {}
|
||||
|
||||
void SetCoreData(const CoreData&) override {}
|
||||
};
|
||||
|
||||
struct NoAccel : virtual DataReportManipulator
|
||||
{
|
||||
bool HasAccel() const override { return false; }
|
||||
void GetAccelData(AccelData* accel) const override {}
|
||||
void SetAccelData(const AccelData& accel) override {}
|
||||
};
|
||||
|
||||
// Handles typical non-interleaved accel data:
|
||||
struct IncludeAccel : virtual DataReportManipulator
|
||||
{
|
||||
void GetAccelData(AccelData* result) const override
|
||||
{
|
||||
const AccelMSB accel = Common::BitCastPtr<AccelMSB>(data_ptr + 2);
|
||||
result->x = accel.x << 2;
|
||||
result->y = accel.y << 2;
|
||||
result->z = accel.z << 2;
|
||||
|
||||
// LSBs
|
||||
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
result->x |= core.acc_bits & 0b11;
|
||||
result->y |= (core.acc_bits2 & 0b1) << 1;
|
||||
result->z |= core.acc_bits2 & 0b10;
|
||||
}
|
||||
|
||||
void SetAccelData(const AccelData& new_accel) override
|
||||
{
|
||||
AccelMSB accel = {};
|
||||
accel.x = new_accel.x >> 2;
|
||||
accel.y = new_accel.y >> 2;
|
||||
accel.z = new_accel.z >> 2;
|
||||
Common::BitCastPtr<AccelMSB>(data_ptr + 2) = accel;
|
||||
|
||||
// LSBs
|
||||
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
core.acc_bits = (new_accel.x >> 0) & 0b11;
|
||||
core.acc_bits2 = (new_accel.y >> 1) & 0x1;
|
||||
core.acc_bits2 |= (new_accel.z & 0xb10);
|
||||
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||
}
|
||||
|
||||
bool HasAccel() const override { return true; }
|
||||
|
||||
private:
|
||||
struct AccelMSB
|
||||
{
|
||||
u8 x, y, z;
|
||||
};
|
||||
static_assert(sizeof(AccelMSB) == 3, "Wrong size");
|
||||
};
|
||||
|
||||
template <u32 Offset, u32 Length>
|
||||
struct IncludeExt : virtual DataReportManipulator
|
||||
{
|
||||
u32 GetExtDataSize() const override { return Length; }
|
||||
const u8* GetExtDataPtr() const override { return data_ptr + Offset; }
|
||||
u8* GetExtDataPtr() override { return data_ptr + Offset; }
|
||||
|
||||
// Any report that has Extension data has it last.
|
||||
u32 GetDataSize() const override { return Offset + Length; }
|
||||
};
|
||||
|
||||
struct NoExt : virtual DataReportManipulator
|
||||
{
|
||||
u32 GetExtDataSize() const override { return 0; }
|
||||
const u8* GetExtDataPtr() const override { return nullptr; }
|
||||
u8* GetExtDataPtr() override { return nullptr; }
|
||||
};
|
||||
|
||||
template <u32 Offset, u32 Length, u32 DataOffset = 0>
|
||||
struct IncludeIR : virtual DataReportManipulator
|
||||
{
|
||||
u32 GetIRDataSize() const override { return Length; }
|
||||
const u8* GetIRDataPtr() const override { return data_ptr + Offset; }
|
||||
u8* GetIRDataPtr() override { return data_ptr + Offset; }
|
||||
u32 GetIRDataFormatOffset() const override { return DataOffset; }
|
||||
};
|
||||
|
||||
struct NoIR : virtual DataReportManipulator
|
||||
{
|
||||
u32 GetIRDataSize() const override { return 0; }
|
||||
const u8* GetIRDataPtr() const override { return nullptr; }
|
||||
u8* GetIRDataPtr() override { return nullptr; }
|
||||
u32 GetIRDataFormatOffset() const override { return 0; }
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
// Disable warning for inheritance via dominance
|
||||
#pragma warning(disable : 4250)
|
||||
#endif
|
||||
|
||||
struct ReportCore : IncludeCore, NoAccel, NoIR, NoExt
|
||||
{
|
||||
u32 GetDataSize() const override { return 2; }
|
||||
};
|
||||
|
||||
struct ReportCoreAccel : IncludeCore, IncludeAccel, NoIR, NoExt
|
||||
{
|
||||
u32 GetDataSize() const override { return 5; }
|
||||
};
|
||||
|
||||
struct ReportCoreExt8 : IncludeCore, NoAccel, NoIR, IncludeExt<5, 8>
|
||||
{
|
||||
};
|
||||
|
||||
struct ReportCoreAccelIR12 : IncludeCore, IncludeAccel, IncludeIR<5, 12>, NoExt
|
||||
{
|
||||
u32 GetDataSize() const override { return 17; }
|
||||
};
|
||||
|
||||
struct ReportCoreExt19 : IncludeCore, NoAccel, NoIR, IncludeExt<2, 19>
|
||||
{
|
||||
};
|
||||
|
||||
struct ReportCoreAccelExt16 : IncludeCore, IncludeAccel, NoIR, IncludeExt<5, 16>
|
||||
{
|
||||
};
|
||||
|
||||
struct ReportCoreIR10Ext9 : IncludeCore, NoAccel, IncludeIR<2, 10>, IncludeExt<12, 9>
|
||||
{
|
||||
};
|
||||
|
||||
struct ReportCoreAccelIR10Ext6 : IncludeCore, IncludeAccel, IncludeIR<5, 10>, IncludeExt<15, 6>
|
||||
{
|
||||
};
|
||||
|
||||
struct ReportExt21 : NoCore, NoAccel, NoIR, IncludeExt<0, 21>
|
||||
{
|
||||
};
|
||||
|
||||
struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt
|
||||
{
|
||||
// FYI: Only 8-bits of precision in this report, and no Y axis.
|
||||
// Only contains 4 MSB of Z axis.
|
||||
|
||||
void GetAccelData(AccelData* accel) const override
|
||||
{
|
||||
accel->x = data_ptr[2] << 2;
|
||||
|
||||
// Retain lower 6 bits.
|
||||
accel->z &= 0b111111;
|
||||
|
||||
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
accel->z |= (core.acc_bits << 6) | (core.acc_bits2 << 8);
|
||||
}
|
||||
|
||||
void SetAccelData(const AccelData& accel) override
|
||||
{
|
||||
data_ptr[2] = accel.x >> 2;
|
||||
|
||||
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
core.acc_bits = (accel.z >> 6) & 0b11;
|
||||
core.acc_bits2 = (accel.z >> 8) & 0b11;
|
||||
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||
}
|
||||
|
||||
bool HasAccel() const override { return true; }
|
||||
|
||||
u32 GetDataSize() const override { return 21; }
|
||||
};
|
||||
|
||||
struct ReportInterleave2 : IncludeCore, IncludeIR<3, 18, 18>, NoExt
|
||||
{
|
||||
// FYI: Only 8-bits of precision in this report, and no X axis.
|
||||
// Only contains 4 LSB of Z axis.
|
||||
|
||||
void GetAccelData(AccelData* accel) const override
|
||||
{
|
||||
accel->y = data_ptr[2] << 2;
|
||||
|
||||
// Retain upper 4 bits.
|
||||
accel->z &= ~0b111111;
|
||||
|
||||
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
accel->z |= (core.acc_bits << 2) | (core.acc_bits2 << 4);
|
||||
}
|
||||
|
||||
void SetAccelData(const AccelData& accel) override
|
||||
{
|
||||
data_ptr[2] = accel.y >> 2;
|
||||
|
||||
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||
core.acc_bits = (accel.z >> 2) & 0b11;
|
||||
core.acc_bits2 = (accel.z >> 4) & 0b11;
|
||||
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||
}
|
||||
|
||||
bool HasAccel() const override { return true; }
|
||||
|
||||
u32 GetDataSize() const override { return 21; }
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
std::unique_ptr<DataReportManipulator> MakeDataReportManipulator(InputReportID rpt_id, u8* data_ptr)
|
||||
{
|
||||
std::unique_ptr<DataReportManipulator> ptr;
|
||||
|
||||
switch (rpt_id)
|
||||
{
|
||||
case InputReportID::ReportCore:
|
||||
// 0x30: Core Buttons
|
||||
ptr = std::make_unique<ReportCore>();
|
||||
break;
|
||||
case InputReportID::ReportCoreAccel:
|
||||
// 0x31: Core Buttons and Accelerometer
|
||||
ptr = std::make_unique<ReportCoreAccel>();
|
||||
break;
|
||||
case InputReportID::ReportCoreExt8:
|
||||
// 0x32: Core Buttons with 8 Extension bytes
|
||||
ptr = std::make_unique<ReportCoreExt8>();
|
||||
break;
|
||||
case InputReportID::ReportCoreAccelIR12:
|
||||
// 0x33: Core Buttons and Accelerometer with 12 IR bytes
|
||||
ptr = std::make_unique<ReportCoreAccelIR12>();
|
||||
break;
|
||||
case InputReportID::ReportCoreExt19:
|
||||
// 0x34: Core Buttons with 19 Extension bytes
|
||||
ptr = std::make_unique<ReportCoreExt19>();
|
||||
break;
|
||||
case InputReportID::ReportCoreAccelExt16:
|
||||
// 0x35: Core Buttons and Accelerometer with 16 Extension Bytes
|
||||
ptr = std::make_unique<ReportCoreAccelExt16>();
|
||||
break;
|
||||
case InputReportID::ReportCoreIR10Ext9:
|
||||
// 0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes
|
||||
ptr = std::make_unique<ReportCoreIR10Ext9>();
|
||||
break;
|
||||
case InputReportID::ReportCoreAccelIR10Ext6:
|
||||
// 0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes
|
||||
ptr = std::make_unique<ReportCoreAccelIR10Ext6>();
|
||||
break;
|
||||
case InputReportID::ReportExt21:
|
||||
// 0x3d: 21 Extension Bytes
|
||||
ptr = std::make_unique<ReportExt21>();
|
||||
break;
|
||||
case InputReportID::ReportInterleave1:
|
||||
// 0x3e - 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
|
||||
ptr = std::make_unique<ReportInterleave1>();
|
||||
break;
|
||||
case InputReportID::ReportInterleave2:
|
||||
ptr = std::make_unique<ReportInterleave2>();
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
ptr->data_ptr = data_ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
DataReportBuilder::DataReportBuilder(InputReportID rpt_id) : m_data(rpt_id)
|
||||
{
|
||||
SetMode(rpt_id);
|
||||
}
|
||||
|
||||
void DataReportBuilder::SetMode(InputReportID rpt_id)
|
||||
{
|
||||
m_data.report_id = rpt_id;
|
||||
m_manip = MakeDataReportManipulator(rpt_id, GetDataPtr() + HEADER_SIZE);
|
||||
}
|
||||
|
||||
InputReportID DataReportBuilder::GetMode() const
|
||||
{
|
||||
return m_data.report_id;
|
||||
}
|
||||
|
||||
bool DataReportBuilder::IsValidMode(InputReportID mode)
|
||||
{
|
||||
return (mode >= InputReportID::ReportCore && mode <= InputReportID::ReportCoreAccelIR10Ext6) ||
|
||||
(mode >= InputReportID::ReportExt21 && InputReportID::ReportInterleave2 <= mode);
|
||||
}
|
||||
|
||||
bool DataReportBuilder::HasCore() const
|
||||
{
|
||||
return m_manip->HasCore();
|
||||
}
|
||||
|
||||
bool DataReportBuilder::HasAccel() const
|
||||
{
|
||||
return m_manip->HasAccel();
|
||||
}
|
||||
|
||||
bool DataReportBuilder::HasIR() const
|
||||
{
|
||||
return m_manip->HasIR();
|
||||
}
|
||||
|
||||
bool DataReportBuilder::HasExt() const
|
||||
{
|
||||
return m_manip->HasExt();
|
||||
}
|
||||
|
||||
u32 DataReportBuilder::GetIRDataSize() const
|
||||
{
|
||||
return m_manip->GetIRDataSize();
|
||||
}
|
||||
|
||||
u32 DataReportBuilder::GetExtDataSize() const
|
||||
{
|
||||
return m_manip->GetExtDataSize();
|
||||
}
|
||||
|
||||
u32 DataReportBuilder::GetIRDataFormatOffset() const
|
||||
{
|
||||
return m_manip->GetIRDataFormatOffset();
|
||||
}
|
||||
|
||||
void DataReportBuilder::GetCoreData(CoreData* core) const
|
||||
{
|
||||
m_manip->GetCoreData(core);
|
||||
}
|
||||
|
||||
void DataReportBuilder::SetCoreData(const CoreData& core)
|
||||
{
|
||||
m_manip->SetCoreData(core);
|
||||
}
|
||||
|
||||
void DataReportBuilder::GetAccelData(AccelData* accel) const
|
||||
{
|
||||
m_manip->GetAccelData(accel);
|
||||
}
|
||||
|
||||
void DataReportBuilder::SetAccelData(const AccelData& accel)
|
||||
{
|
||||
m_manip->SetAccelData(accel);
|
||||
}
|
||||
|
||||
const u8* DataReportBuilder::GetDataPtr() const
|
||||
{
|
||||
return m_data.GetData();
|
||||
}
|
||||
|
||||
u8* DataReportBuilder::GetDataPtr()
|
||||
{
|
||||
return m_data.GetData();
|
||||
}
|
||||
|
||||
u32 DataReportBuilder::GetDataSize() const
|
||||
{
|
||||
return m_manip->GetDataSize() + HEADER_SIZE;
|
||||
}
|
||||
|
||||
u8* DataReportBuilder::GetIRDataPtr()
|
||||
{
|
||||
return m_manip->GetIRDataPtr();
|
||||
}
|
||||
|
||||
const u8* DataReportBuilder::GetIRDataPtr() const
|
||||
{
|
||||
return m_manip->GetIRDataPtr();
|
||||
}
|
||||
|
||||
u8* DataReportBuilder::GetExtDataPtr()
|
||||
{
|
||||
return m_manip->GetExtDataPtr();
|
||||
}
|
||||
|
||||
const u8* DataReportBuilder::GetExtDataPtr() const
|
||||
{
|
||||
return m_manip->GetExtDataPtr();
|
||||
}
|
||||
|
||||
} // namespace WiimoteCommon
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
|
||||
namespace WiimoteCommon
|
||||
{
|
||||
// Interface for manipulating Wiimote "Data" reports
|
||||
// If a report does not contain a particular feature the Get/Set is a no-op.
|
||||
class DataReportManipulator
|
||||
{
|
||||
public:
|
||||
virtual ~DataReportManipulator() = default;
|
||||
|
||||
// Accel data handled as if there were always 10 bits of precision.
|
||||
struct AccelData
|
||||
{
|
||||
u16 x, y, z;
|
||||
};
|
||||
|
||||
using CoreData = ButtonData;
|
||||
|
||||
virtual bool HasCore() const = 0;
|
||||
virtual bool HasAccel() const = 0;
|
||||
bool HasIR() const;
|
||||
bool HasExt() const;
|
||||
|
||||
virtual void GetCoreData(CoreData*) const = 0;
|
||||
virtual void GetAccelData(AccelData*) const = 0;
|
||||
|
||||
virtual void SetCoreData(const CoreData&) = 0;
|
||||
virtual void SetAccelData(const AccelData&) = 0;
|
||||
|
||||
virtual u8* GetIRDataPtr() = 0;
|
||||
virtual const u8* GetIRDataPtr() const = 0;
|
||||
virtual u32 GetIRDataSize() const = 0;
|
||||
virtual u32 GetIRDataFormatOffset() const = 0;
|
||||
|
||||
virtual u8* GetExtDataPtr() = 0;
|
||||
virtual const u8* GetExtDataPtr() const = 0;
|
||||
virtual u32 GetExtDataSize() const = 0;
|
||||
|
||||
u8* GetDataPtr();
|
||||
const u8* GetDataPtr() const;
|
||||
|
||||
virtual u32 GetDataSize() const = 0;
|
||||
|
||||
u8* data_ptr;
|
||||
};
|
||||
|
||||
std::unique_ptr<DataReportManipulator> MakeDataReportManipulator(InputReportID rpt_id,
|
||||
u8* data_ptr);
|
||||
|
||||
class DataReportBuilder
|
||||
{
|
||||
public:
|
||||
explicit DataReportBuilder(InputReportID rpt_id);
|
||||
|
||||
using CoreData = ButtonData;
|
||||
using AccelData = DataReportManipulator::AccelData;
|
||||
|
||||
void SetMode(InputReportID rpt_id);
|
||||
InputReportID GetMode() const;
|
||||
|
||||
static bool IsValidMode(InputReportID rpt_id);
|
||||
|
||||
bool HasCore() const;
|
||||
bool HasAccel() const;
|
||||
bool HasIR() const;
|
||||
bool HasExt() const;
|
||||
|
||||
u32 GetIRDataSize() const;
|
||||
u32 GetExtDataSize() const;
|
||||
|
||||
u32 GetIRDataFormatOffset() const;
|
||||
|
||||
void GetCoreData(CoreData*) const;
|
||||
void GetAccelData(AccelData*) const;
|
||||
|
||||
void SetCoreData(const CoreData&);
|
||||
void SetAccelData(const AccelData&);
|
||||
|
||||
u8* GetIRDataPtr();
|
||||
const u8* GetIRDataPtr() const;
|
||||
u8* GetExtDataPtr();
|
||||
const u8* GetExtDataPtr() const;
|
||||
|
||||
u8* GetDataPtr();
|
||||
const u8* GetDataPtr() const;
|
||||
|
||||
u32 GetDataSize() const;
|
||||
|
||||
private:
|
||||
static constexpr int HEADER_SIZE = 2;
|
||||
|
||||
static constexpr int MAX_DATA_SIZE = MAX_PAYLOAD - 2;
|
||||
|
||||
TypedHIDInputData<std::array<u8, MAX_DATA_SIZE>> m_data;
|
||||
|
||||
std::unique_ptr<DataReportManipulator> m_manip;
|
||||
};
|
||||
|
||||
} // namespace WiimoteCommon
|
||||
@@ -4,55 +4,75 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// Wiimote internal codes
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
// Communication channels
|
||||
enum WiimoteChannel
|
||||
namespace WiimoteCommon
|
||||
{
|
||||
WC_OUTPUT = 0x11,
|
||||
WC_INPUT = 0x13
|
||||
constexpr u8 MAX_PAYLOAD = 23;
|
||||
|
||||
enum class InputReportID : u8
|
||||
{
|
||||
Status = 0x20,
|
||||
ReadDataReply = 0x21,
|
||||
Ack = 0x22,
|
||||
|
||||
// Not a real value on the wiimote, just a state to disable reports:
|
||||
ReportDisabled = 0x00,
|
||||
|
||||
ReportCore = 0x30,
|
||||
ReportCoreAccel = 0x31,
|
||||
ReportCoreExt8 = 0x32,
|
||||
ReportCoreAccelIR12 = 0x33,
|
||||
ReportCoreExt19 = 0x34,
|
||||
ReportCoreAccelExt16 = 0x35,
|
||||
ReportCoreIR10Ext9 = 0x36,
|
||||
ReportCoreAccelIR10Ext6 = 0x37,
|
||||
|
||||
ReportExt21 = 0x3d,
|
||||
ReportInterleave1 = 0x3e,
|
||||
ReportInterleave2 = 0x3f,
|
||||
};
|
||||
|
||||
// The 4 most significant bits of the first byte of an outgoing command must be
|
||||
// 0x50 if sending on the command channel and 0xA0 if sending on the interrupt
|
||||
// channel. On Mac and Linux we use interrupt channel; on Windows, command.
|
||||
enum WiimoteReport
|
||||
enum class OutputReportID : u8
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WR_SET_REPORT = 0x50
|
||||
#else
|
||||
WR_SET_REPORT = 0xA0
|
||||
#endif
|
||||
Rumble = 0x10,
|
||||
LED = 0x11,
|
||||
ReportMode = 0x12,
|
||||
IRPixelClock = 0x13,
|
||||
SpeakerEnable = 0x14,
|
||||
RequestStatus = 0x15,
|
||||
WriteData = 0x16,
|
||||
ReadData = 0x17,
|
||||
SpeakerData = 0x18,
|
||||
SpeakerMute = 0x19,
|
||||
IRLogic = 0x1a,
|
||||
};
|
||||
|
||||
enum WiimoteBT
|
||||
enum class LED : u8
|
||||
{
|
||||
BT_INPUT = 0x01,
|
||||
BT_OUTPUT = 0x02
|
||||
};
|
||||
|
||||
// LED bit masks
|
||||
enum WiimoteLED
|
||||
{
|
||||
LED_NONE = 0x00,
|
||||
None = 0x00,
|
||||
LED_1 = 0x10,
|
||||
LED_2 = 0x20,
|
||||
LED_3 = 0x40,
|
||||
LED_4 = 0x80
|
||||
};
|
||||
|
||||
enum WiimoteSpace
|
||||
enum class AddressSpace : u8
|
||||
{
|
||||
WS_EEPROM = 0x00,
|
||||
WS_REGS1 = 0x01,
|
||||
WS_REGS2 = 0x02
|
||||
// FYI: The EEPROM address space is offset 0x0070 on i2c slave 0x50.
|
||||
// However attempting to access this device directly results in an error.
|
||||
EEPROM = 0x00,
|
||||
// 0x01 is never used but it does function on a real wiimote:
|
||||
I2CBusAlt = 0x01,
|
||||
I2CBus = 0x02,
|
||||
};
|
||||
|
||||
enum WiimoteReadError
|
||||
enum class ErrorCode : u8
|
||||
{
|
||||
RDERR_WOREG = 7,
|
||||
RDERR_NOMEM = 8
|
||||
Success = 0,
|
||||
InvalidSpace = 6,
|
||||
Nack = 7,
|
||||
InvalidAddress = 8,
|
||||
};
|
||||
|
||||
constexpr u8 MAX_PAYLOAD = 23;
|
||||
constexpr u32 WIIMOTE_DEFAULT_TIMEOUT = 1000;
|
||||
} // namespace WiimoteCommon
|
||||
|
||||
@@ -5,22 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4200)
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// Source: HID_010_SPC_PFL/1.0 (official HID specification)
|
||||
|
||||
struct hid_packet
|
||||
namespace WiimoteCommon
|
||||
{
|
||||
u8 param : 4;
|
||||
u8 type : 4;
|
||||
u8 data[0];
|
||||
};
|
||||
// Source: HID_010_SPC_PFL/1.0 (official HID specification)
|
||||
|
||||
constexpr u8 HID_TYPE_HANDSHAKE = 0;
|
||||
constexpr u8 HID_TYPE_SET_REPORT = 5;
|
||||
@@ -31,8 +21,55 @@ constexpr u8 HID_HANDSHAKE_SUCCESS = 0;
|
||||
constexpr u8 HID_PARAM_INPUT = 1;
|
||||
constexpr u8 HID_PARAM_OUTPUT = 2;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
// Disable warning for zero-sized array:
|
||||
#pragma warning(disable : 4200)
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct HIDPacket
|
||||
{
|
||||
static constexpr int HEADER_SIZE = 1;
|
||||
|
||||
u8 param : 4;
|
||||
u8 type : 4;
|
||||
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypedHIDInputData
|
||||
{
|
||||
TypedHIDInputData(InputReportID _rpt_id)
|
||||
: param(HID_PARAM_INPUT), type(HID_TYPE_DATA), report_id(_rpt_id)
|
||||
{
|
||||
}
|
||||
|
||||
u8 param : 4;
|
||||
u8 type : 4;
|
||||
|
||||
InputReportID report_id;
|
||||
|
||||
T data;
|
||||
|
||||
static_assert(std::is_pod<T>());
|
||||
|
||||
u8* GetData() { return reinterpret_cast<u8*>(this); }
|
||||
const u8* GetData() const { return reinterpret_cast<const u8*>(this); }
|
||||
|
||||
constexpr u32 GetSize() const
|
||||
{
|
||||
static_assert(sizeof(*this) == sizeof(T) + 2);
|
||||
return sizeof(*this);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace WiimoteCommon
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,79 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Attachment/Attachment.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Compiler.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Extension.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
// Extension device IDs to be written to the last bytes of the extension reg
|
||||
// The id for nothing inserted
|
||||
constexpr std::array<u8, 6> nothing_id{{0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e}};
|
||||
// The id for a partially inserted extension (currently unused)
|
||||
DOLPHIN_UNUSED constexpr std::array<u8, 6> partially_id{{0x00, 0x00, 0x00, 0x00, 0xff, 0xff}};
|
||||
|
||||
Attachment::Attachment(const char* const name, ExtensionReg& reg) : m_name(name), m_reg(reg)
|
||||
{
|
||||
}
|
||||
|
||||
None::None(ExtensionReg& reg) : Attachment("None", reg)
|
||||
{
|
||||
// set up register
|
||||
m_id = nothing_id;
|
||||
}
|
||||
|
||||
void Attachment::GetState(u8* const data)
|
||||
{
|
||||
}
|
||||
|
||||
bool Attachment::IsButtonPressed() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Attachment::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void Attachment::Reset()
|
||||
{
|
||||
// set up register
|
||||
m_reg = {};
|
||||
std::copy(m_id.cbegin(), m_id.cend(), m_reg.constant_id);
|
||||
std::copy(m_calibration.cbegin(), m_calibration.cend(), m_reg.calibration);
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
namespace ControllerEmu
|
||||
{
|
||||
void Extension::GetState(u8* const data)
|
||||
{
|
||||
static_cast<WiimoteEmu::Attachment*>(attachments[active_extension].get())->GetState(data);
|
||||
}
|
||||
|
||||
bool Extension::IsButtonPressed() const
|
||||
{
|
||||
// Extension == 0 means no Extension, > 0 means one is connected
|
||||
// Since we want to use this to know if disconnected Wiimotes want to be connected, and
|
||||
// disconnected
|
||||
// Wiimotes (can? always?) have their active_extension set to -1, we also have to check the
|
||||
// switch_extension
|
||||
if (active_extension > 0)
|
||||
return static_cast<WiimoteEmu::Attachment*>(attachments[active_extension].get())
|
||||
->IsButtonPressed();
|
||||
if (switch_extension > 0)
|
||||
return static_cast<WiimoteEmu::Attachment*>(attachments[switch_extension].get())
|
||||
->IsButtonPressed();
|
||||
return false;
|
||||
}
|
||||
} // namespace ControllerEmu
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
struct ExtensionReg;
|
||||
|
||||
class Attachment : public ControllerEmu::EmulatedController
|
||||
{
|
||||
public:
|
||||
Attachment(const char* const name, ExtensionReg& reg);
|
||||
|
||||
virtual void GetState(u8* const data);
|
||||
virtual bool IsButtonPressed() const;
|
||||
|
||||
void Reset();
|
||||
std::string GetName() const override;
|
||||
|
||||
protected:
|
||||
std::array<u8, 6> m_id{};
|
||||
std::array<u8, 0x10> m_calibration{};
|
||||
|
||||
private:
|
||||
const char* const m_name;
|
||||
ExtensionReg& m_reg;
|
||||
};
|
||||
|
||||
class None : public Attachment
|
||||
{
|
||||
public:
|
||||
explicit None(ExtensionReg& reg);
|
||||
};
|
||||
} // namespace WiimoteEmu
|
||||
@@ -0,0 +1,213 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Camera.h"
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
#include "Core/HW/WiimoteEmu/MatrixMath.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
void CameraLogic::Reset()
|
||||
{
|
||||
reg_data = {};
|
||||
}
|
||||
|
||||
void CameraLogic::DoState(PointerWrap& p)
|
||||
{
|
||||
p.Do(reg_data);
|
||||
}
|
||||
|
||||
int CameraLogic::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
|
||||
{
|
||||
if (I2C_ADDR != slave_addr)
|
||||
return 0;
|
||||
|
||||
return RawRead(®_data, addr, count, data_out);
|
||||
}
|
||||
|
||||
int CameraLogic::BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in)
|
||||
{
|
||||
if (I2C_ADDR != slave_addr)
|
||||
return 0;
|
||||
|
||||
return RawWrite(®_data, addr, count, data_in);
|
||||
}
|
||||
|
||||
void CameraLogic::Update(const ControllerEmu::Cursor::StateData& cursor,
|
||||
const NormalizedAccelData& accel, bool sensor_bar_on_top)
|
||||
{
|
||||
double nsin, ncos;
|
||||
|
||||
// Ugly code to figure out the wiimote's current angle.
|
||||
// TODO: Kill this.
|
||||
double ax = accel.x;
|
||||
double az = accel.z;
|
||||
const double len = sqrt(ax * ax + az * az);
|
||||
|
||||
if (len)
|
||||
{
|
||||
ax /= len;
|
||||
az /= len; // normalizing the vector
|
||||
nsin = ax;
|
||||
ncos = az;
|
||||
}
|
||||
else
|
||||
{
|
||||
nsin = 0;
|
||||
ncos = 1;
|
||||
}
|
||||
|
||||
const double ir_sin = nsin;
|
||||
const double ir_cos = ncos;
|
||||
|
||||
static constexpr int camWidth = 1024;
|
||||
static constexpr int camHeight = 768;
|
||||
static constexpr double bndleft = 0.78820266;
|
||||
static constexpr double bndright = -0.78820266;
|
||||
static constexpr double dist1 = 100.0 / camWidth; // this seems the optimal distance for zelda
|
||||
static constexpr double dist2 = 1.2 * dist1;
|
||||
|
||||
constexpr int NUM_POINTS = 4;
|
||||
|
||||
std::array<Vertex, NUM_POINTS> v;
|
||||
|
||||
for (auto& vtx : v)
|
||||
{
|
||||
vtx.x = cursor.x * (bndright - bndleft) / 2 + (bndleft + bndright) / 2;
|
||||
|
||||
static constexpr double bndup = -0.315447;
|
||||
static constexpr double bnddown = 0.85;
|
||||
|
||||
if (sensor_bar_on_top)
|
||||
vtx.y = cursor.y * (bndup - bnddown) / 2 + (bndup + bnddown) / 2;
|
||||
else
|
||||
vtx.y = cursor.y * (bndup - bnddown) / 2 - (bndup + bnddown) / 2;
|
||||
|
||||
vtx.z = 0;
|
||||
}
|
||||
|
||||
v[0].x -= (cursor.z * 0.5 + 1) * dist1;
|
||||
v[1].x += (cursor.z * 0.5 + 1) * dist1;
|
||||
v[2].x -= (cursor.z * 0.5 + 1) * dist2;
|
||||
v[3].x += (cursor.z * 0.5 + 1) * dist2;
|
||||
|
||||
#define printmatrix(m) \
|
||||
PanicAlert("%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", m[0][0], m[0][1], m[0][2], \
|
||||
m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], \
|
||||
m[3][0], m[3][1], m[3][2], m[3][3])
|
||||
Matrix rot, tot;
|
||||
static Matrix scale;
|
||||
MatrixScale(scale, 1, camWidth / camHeight, 1);
|
||||
MatrixRotationByZ(rot, ir_sin, ir_cos);
|
||||
MatrixMultiply(tot, scale, rot);
|
||||
|
||||
u16 x[NUM_POINTS], y[NUM_POINTS];
|
||||
memset(x, 0xFF, sizeof(x));
|
||||
memset(y, 0xFF, sizeof(y));
|
||||
|
||||
for (std::size_t i = 0; i < v.size(); i++)
|
||||
{
|
||||
MatrixTransformVertex(tot, v[i]);
|
||||
|
||||
if ((v[i].x < -1) || (v[i].x > 1) || (v[i].y < -1) || (v[i].y > 1))
|
||||
continue;
|
||||
|
||||
x[i] = static_cast<u16>(lround((v[i].x + 1) / 2 * (camWidth - 1)));
|
||||
y[i] = static_cast<u16>(lround((v[i].y + 1) / 2 * (camHeight - 1)));
|
||||
|
||||
if (x[i] >= camWidth || y[i] >= camHeight)
|
||||
{
|
||||
x[i] = -1;
|
||||
y[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// IR data is read from offset 0x37 on real hardware
|
||||
auto& data = reg_data.camera_data;
|
||||
// A maximum of 36 bytes:
|
||||
std::fill(std::begin(data), std::end(data), 0xff);
|
||||
|
||||
// Fill report with valid data when full handshake was done
|
||||
// TODO: kill magic number:
|
||||
if (reg_data.data[0x30])
|
||||
{
|
||||
switch (reg_data.mode)
|
||||
{
|
||||
case IR_MODE_BASIC:
|
||||
for (unsigned int i = 0; i < 2; ++i)
|
||||
{
|
||||
IRBasic irdata = {};
|
||||
|
||||
irdata.x1 = static_cast<u8>(x[i * 2]);
|
||||
irdata.x1hi = x[i * 2] >> 8;
|
||||
irdata.y1 = static_cast<u8>(y[i * 2]);
|
||||
irdata.y1hi = y[i * 2] >> 8;
|
||||
|
||||
irdata.x2 = static_cast<u8>(x[i * 2 + 1]);
|
||||
irdata.x2hi = x[i * 2 + 1] >> 8;
|
||||
irdata.y2 = static_cast<u8>(y[i * 2 + 1]);
|
||||
irdata.y2hi = y[i * 2 + 1] >> 8;
|
||||
|
||||
Common::BitCastPtr<IRBasic>(data + i * sizeof(IRBasic)) = irdata;
|
||||
}
|
||||
break;
|
||||
case IR_MODE_EXTENDED:
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (x[i] < camWidth)
|
||||
{
|
||||
IRExtended irdata = {};
|
||||
|
||||
irdata.x = static_cast<u8>(x[i]);
|
||||
irdata.xhi = x[i] >> 8;
|
||||
|
||||
irdata.y = static_cast<u8>(y[i]);
|
||||
irdata.yhi = y[i] >> 8;
|
||||
|
||||
irdata.size = 10;
|
||||
|
||||
Common::BitCastPtr<IRExtended>(data + i * sizeof(IRExtended)) = irdata;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IR_MODE_FULL:
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (x[i] < camWidth)
|
||||
{
|
||||
IRFull irdata = {};
|
||||
|
||||
irdata.x = static_cast<u8>(x[i]);
|
||||
irdata.xhi = x[i] >> 8;
|
||||
|
||||
irdata.y = static_cast<u8>(y[i]);
|
||||
irdata.yhi = y[i] >> 8;
|
||||
|
||||
irdata.size = 10;
|
||||
|
||||
// TODO: implement these sensibly:
|
||||
// TODO: do high bits of x/y min/max need to be set to zero?
|
||||
irdata.xmin = 0;
|
||||
irdata.ymin = 0;
|
||||
irdata.xmax = 0;
|
||||
irdata.ymax = 0;
|
||||
irdata.zero = 0;
|
||||
irdata.intensity = 0;
|
||||
|
||||
Common::BitCastPtr<IRFull>(data + i * sizeof(IRFull)) = irdata;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// This seems to be fairly common, 0xff data is sent in this case:
|
||||
// WARN_LOG(WIIMOTE, "Game is requesting IR data before setting IR mode.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/WiimoteEmu/Dynamics.h"
|
||||
#include "Core/HW/WiimoteEmu/I2CBus.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Cursor.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
// Four bytes for two objects. Filled with 0xFF if empty
|
||||
struct IRBasic
|
||||
{
|
||||
u8 x1;
|
||||
u8 y1;
|
||||
u8 x2hi : 2;
|
||||
u8 y2hi : 2;
|
||||
u8 x1hi : 2;
|
||||
u8 y1hi : 2;
|
||||
u8 x2;
|
||||
u8 y2;
|
||||
};
|
||||
static_assert(sizeof(IRBasic) == 5, "Wrong size");
|
||||
|
||||
// Three bytes for one object
|
||||
struct IRExtended
|
||||
{
|
||||
u8 x;
|
||||
u8 y;
|
||||
u8 size : 4;
|
||||
u8 xhi : 2;
|
||||
u8 yhi : 2;
|
||||
};
|
||||
static_assert(sizeof(IRExtended) == 3, "Wrong size");
|
||||
|
||||
// Nine bytes for one object
|
||||
// first 3 bytes are the same as extended
|
||||
struct IRFull : IRExtended
|
||||
{
|
||||
u8 xmin : 7;
|
||||
u8 : 1;
|
||||
u8 ymin : 7;
|
||||
u8 : 1;
|
||||
u8 xmax : 7;
|
||||
u8 : 1;
|
||||
u8 ymax : 7;
|
||||
u8 : 1;
|
||||
u8 zero;
|
||||
u8 intensity;
|
||||
};
|
||||
static_assert(sizeof(IRFull) == 9, "Wrong size");
|
||||
|
||||
class CameraLogic : public I2CSlave
|
||||
{
|
||||
public:
|
||||
enum : u8
|
||||
{
|
||||
IR_MODE_BASIC = 1,
|
||||
IR_MODE_EXTENDED = 3,
|
||||
IR_MODE_FULL = 5,
|
||||
};
|
||||
|
||||
void Reset();
|
||||
void DoState(PointerWrap& p);
|
||||
void Update(const ControllerEmu::Cursor::StateData& cursor, const NormalizedAccelData& accel,
|
||||
bool sensor_bar_on_top);
|
||||
|
||||
static constexpr u8 I2C_ADDR = 0x58;
|
||||
|
||||
private:
|
||||
// TODO: some of this memory is write-only and should return error 7.
|
||||
#pragma pack(push, 1)
|
||||
struct Register
|
||||
{
|
||||
// Contains sensitivity and other unknown data
|
||||
// TODO: Do the IR and Camera enabling reports write to the i2c bus?
|
||||
// TODO: Does disabling the camera peripheral reset the mode or sensitivity?
|
||||
// TODO: Break out this "data" array into some known members
|
||||
u8 data[0x33];
|
||||
u8 mode;
|
||||
u8 unk[3];
|
||||
// addr: 0x37
|
||||
u8 camera_data[36];
|
||||
u8 unk2[165];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(0x100 == sizeof(Register));
|
||||
|
||||
public:
|
||||
// The real wiimote reads camera data from the i2c bus at offset 0x37:
|
||||
static const u8 REPORT_DATA_OFFSET = offsetof(Register, camera_data);
|
||||
|
||||
private:
|
||||
int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) override;
|
||||
int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) override;
|
||||
|
||||
Register reg_data;
|
||||
};
|
||||
} // namespace WiimoteEmu
|
||||
@@ -0,0 +1,264 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Dynamics.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Core/Config/WiimoteInputSettings.h"
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
constexpr int SHAKE_FREQ = 6;
|
||||
// Frame count of one up/down shake
|
||||
// < 9 no shake detection in "Wario Land: Shake It"
|
||||
constexpr int SHAKE_STEP_MAX = ::Wiimote::UPDATE_FREQ / SHAKE_FREQ;
|
||||
|
||||
void EmulateShake(NormalizedAccelData* const accel, ControllerEmu::Buttons* const buttons_group,
|
||||
const double intensity, u8* const shake_step)
|
||||
{
|
||||
// shake is a bitfield of X,Y,Z shake button states
|
||||
static const unsigned int btns[] = {0x01, 0x02, 0x04};
|
||||
unsigned int shake = 0;
|
||||
buttons_group->GetState(&shake, btns);
|
||||
|
||||
for (int i = 0; i != 3; ++i)
|
||||
{
|
||||
if (shake & (1 << i))
|
||||
{
|
||||
(&(accel->x))[i] += std::sin(MathUtil::TAU * shake_step[i] / SHAKE_STEP_MAX) * intensity;
|
||||
shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
shake_step[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmulateDynamicShake(NormalizedAccelData* const accel, DynamicData& dynamic_data,
|
||||
ControllerEmu::Buttons* const buttons_group,
|
||||
const DynamicConfiguration& config, u8* const shake_step)
|
||||
{
|
||||
// shake is a bitfield of X,Y,Z shake button states
|
||||
static const unsigned int btns[] = {0x01, 0x02, 0x04};
|
||||
unsigned int shake = 0;
|
||||
buttons_group->GetState(&shake, btns);
|
||||
|
||||
for (int i = 0; i != 3; ++i)
|
||||
{
|
||||
if ((shake & (1 << i)) && dynamic_data.executing_frames_left[i] == 0)
|
||||
{
|
||||
dynamic_data.timing[i]++;
|
||||
}
|
||||
else if (dynamic_data.executing_frames_left[i] > 0)
|
||||
{
|
||||
(&(accel->x))[i] +=
|
||||
std::sin(MathUtil::TAU * shake_step[i] / SHAKE_STEP_MAX) * dynamic_data.intensity[i];
|
||||
shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX;
|
||||
dynamic_data.executing_frames_left[i]--;
|
||||
}
|
||||
else if (shake == 0 && dynamic_data.timing[i] > 0)
|
||||
{
|
||||
if (dynamic_data.timing[i] > config.frames_needed_for_high_intensity)
|
||||
{
|
||||
dynamic_data.intensity[i] = config.high_intensity;
|
||||
}
|
||||
else if (dynamic_data.timing[i] < config.frames_needed_for_low_intensity)
|
||||
{
|
||||
dynamic_data.intensity[i] = config.low_intensity;
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamic_data.intensity[i] = config.med_intensity;
|
||||
}
|
||||
dynamic_data.timing[i] = 0;
|
||||
dynamic_data.executing_frames_left[i] = config.frames_to_execute;
|
||||
}
|
||||
else
|
||||
{
|
||||
shake_step[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmulateTilt(NormalizedAccelData* const accel, ControllerEmu::Tilt* const tilt_group,
|
||||
const bool sideways, const bool upright)
|
||||
{
|
||||
// 180 degrees
|
||||
const ControllerEmu::Tilt::StateData state = tilt_group->GetState();
|
||||
const ControlState roll = state.x * MathUtil::PI;
|
||||
const ControlState pitch = state.y * MathUtil::PI;
|
||||
|
||||
// Some notes that no one will understand but me :p
|
||||
// left, forward, up
|
||||
// lr/ left == negative for all orientations
|
||||
// ud/ up == negative for upright longways
|
||||
// fb/ forward == positive for (sideways flat)
|
||||
|
||||
// Determine which axis is which direction
|
||||
const u32 ud = upright ? (sideways ? 0 : 1) : 2;
|
||||
const u32 lr = sideways;
|
||||
const u32 fb = upright ? 2 : (sideways ? 0 : 1);
|
||||
|
||||
// Sign fix
|
||||
std::array<int, 3> sgn{{-1, 1, 1}};
|
||||
if (sideways && !upright)
|
||||
sgn[fb] *= -1;
|
||||
if (!sideways && upright)
|
||||
sgn[ud] *= -1;
|
||||
|
||||
(&accel->x)[ud] = (sin((MathUtil::PI / 2) - std::max(fabs(roll), fabs(pitch)))) * sgn[ud];
|
||||
(&accel->x)[lr] = -sin(roll) * sgn[lr];
|
||||
(&accel->x)[fb] = sin(pitch) * sgn[fb];
|
||||
}
|
||||
|
||||
void EmulateSwing(NormalizedAccelData* const accel, ControllerEmu::Force* const swing_group,
|
||||
const double intensity, const bool sideways, const bool upright)
|
||||
{
|
||||
const ControllerEmu::Force::StateData swing = swing_group->GetState();
|
||||
|
||||
// Determine which axis is which direction
|
||||
const std::array<int, 3> axis_map{{
|
||||
upright ? (sideways ? 0 : 1) : 2, // up/down
|
||||
sideways, // left/right
|
||||
upright ? 2 : (sideways ? 0 : 1), // forward/backward
|
||||
}};
|
||||
|
||||
// Some orientations have up as positive, some as negative
|
||||
// same with forward
|
||||
std::array<s8, 3> g_dir{{-1, -1, -1}};
|
||||
if (sideways && !upright)
|
||||
g_dir[axis_map[2]] *= -1;
|
||||
if (!sideways && upright)
|
||||
g_dir[axis_map[0]] *= -1;
|
||||
|
||||
for (std::size_t i = 0; i < swing.size(); ++i)
|
||||
(&accel->x)[axis_map[i]] += swing[i] * g_dir[i] * intensity;
|
||||
}
|
||||
|
||||
void EmulateDynamicSwing(NormalizedAccelData* const accel, DynamicData& dynamic_data,
|
||||
ControllerEmu::Force* const swing_group,
|
||||
const DynamicConfiguration& config, const bool sideways,
|
||||
const bool upright)
|
||||
{
|
||||
const ControllerEmu::Force::StateData swing = swing_group->GetState();
|
||||
|
||||
// Determine which axis is which direction
|
||||
const std::array<int, 3> axis_map{{
|
||||
upright ? (sideways ? 0 : 1) : 2, // up/down
|
||||
sideways, // left/right
|
||||
upright ? 2 : (sideways ? 0 : 1), // forward/backward
|
||||
}};
|
||||
|
||||
// Some orientations have up as positive, some as negative
|
||||
// same with forward
|
||||
std::array<s8, 3> g_dir{{-1, -1, -1}};
|
||||
if (sideways && !upright)
|
||||
g_dir[axis_map[2]] *= -1;
|
||||
if (!sideways && upright)
|
||||
g_dir[axis_map[0]] *= -1;
|
||||
|
||||
for (std::size_t i = 0; i < swing.size(); ++i)
|
||||
{
|
||||
if (swing[i] > 0 && dynamic_data.executing_frames_left[i] == 0)
|
||||
{
|
||||
dynamic_data.timing[i]++;
|
||||
}
|
||||
else if (dynamic_data.executing_frames_left[i] > 0)
|
||||
{
|
||||
(&accel->x)[axis_map[i]] += g_dir[i] * dynamic_data.intensity[i];
|
||||
dynamic_data.executing_frames_left[i]--;
|
||||
}
|
||||
else if (swing[i] == 0 && dynamic_data.timing[i] > 0)
|
||||
{
|
||||
if (dynamic_data.timing[i] > config.frames_needed_for_high_intensity)
|
||||
{
|
||||
dynamic_data.intensity[i] = config.high_intensity;
|
||||
}
|
||||
else if (dynamic_data.timing[i] < config.frames_needed_for_low_intensity)
|
||||
{
|
||||
dynamic_data.intensity[i] = config.low_intensity;
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamic_data.intensity[i] = config.med_intensity;
|
||||
}
|
||||
dynamic_data.timing[i] = 0;
|
||||
dynamic_data.executing_frames_left[i] = config.frames_to_execute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WiimoteCommon::DataReportBuilder::AccelData DenormalizeAccelData(const NormalizedAccelData& accel,
|
||||
u16 zero_g, u16 one_g)
|
||||
{
|
||||
const u8 accel_range = one_g - zero_g;
|
||||
|
||||
const s32 unclamped_x = (s32)(accel.x * accel_range + zero_g);
|
||||
const s32 unclamped_y = (s32)(accel.y * accel_range + zero_g);
|
||||
const s32 unclamped_z = (s32)(accel.z * accel_range + zero_g);
|
||||
|
||||
WiimoteCommon::DataReportBuilder::AccelData result;
|
||||
|
||||
result.x = MathUtil::Clamp<u16>(unclamped_x, 0, 0x3ff);
|
||||
result.y = MathUtil::Clamp<u16>(unclamped_y, 0, 0x3ff);
|
||||
result.z = MathUtil::Clamp<u16>(unclamped_z, 0, 0x3ff);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Wiimote::GetAccelData(NormalizedAccelData* accel)
|
||||
{
|
||||
const bool is_sideways = IsSideways();
|
||||
const bool is_upright = IsUpright();
|
||||
|
||||
EmulateTilt(accel, m_tilt, is_sideways, is_upright);
|
||||
|
||||
DynamicConfiguration swing_config;
|
||||
swing_config.low_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_SLOW);
|
||||
swing_config.med_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM);
|
||||
swing_config.high_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_FAST);
|
||||
swing_config.frames_needed_for_high_intensity =
|
||||
Config::Get(Config::WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_FAST);
|
||||
swing_config.frames_needed_for_low_intensity =
|
||||
Config::Get(Config::WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_SLOW);
|
||||
swing_config.frames_to_execute = Config::Get(Config::WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_LENGTH);
|
||||
|
||||
EmulateSwing(accel, m_swing, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM),
|
||||
is_sideways, is_upright);
|
||||
EmulateSwing(accel, m_swing_slow, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_SLOW),
|
||||
is_sideways, is_upright);
|
||||
EmulateSwing(accel, m_swing_fast, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_FAST),
|
||||
is_sideways, is_upright);
|
||||
EmulateDynamicSwing(accel, m_swing_dynamic_data, m_swing_dynamic, swing_config, is_sideways,
|
||||
is_upright);
|
||||
|
||||
DynamicConfiguration shake_config;
|
||||
shake_config.low_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT);
|
||||
shake_config.med_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM);
|
||||
shake_config.high_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD);
|
||||
shake_config.frames_needed_for_high_intensity =
|
||||
Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD);
|
||||
shake_config.frames_needed_for_low_intensity =
|
||||
Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT);
|
||||
shake_config.frames_to_execute = Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH);
|
||||
|
||||
EmulateShake(accel, m_shake, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM),
|
||||
m_shake_step.data());
|
||||
EmulateShake(accel, m_shake_soft, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT),
|
||||
m_shake_soft_step.data());
|
||||
EmulateShake(accel, m_shake_hard, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD),
|
||||
m_shake_hard_step.data());
|
||||
EmulateDynamicShake(accel, m_shake_dynamic_data, m_shake_dynamic, shake_config,
|
||||
m_shake_dynamic_step.data());
|
||||
}
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "Core/HW/WiimoteCommon/DataReport.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
struct NormalizedAccelData
|
||||
{
|
||||
// Unit is 1G
|
||||
double x, y, z;
|
||||
};
|
||||
|
||||
// Used for a dynamic swing or shake
|
||||
struct DynamicData
|
||||
{
|
||||
std::array<int, 3> timing; // Hold length in frames for each axis
|
||||
std::array<double, 3> intensity; // Swing or shake intensity
|
||||
std::array<int, 3> executing_frames_left; // Number of frames to execute the intensity operation
|
||||
};
|
||||
|
||||
// Used for a dynamic swing or shake.
|
||||
// This is used to pass in data that defines the dynamic action
|
||||
struct DynamicConfiguration
|
||||
{
|
||||
double low_intensity;
|
||||
int frames_needed_for_low_intensity;
|
||||
|
||||
double med_intensity;
|
||||
// Frames needed for med intensity can be calculated between high & low
|
||||
|
||||
double high_intensity;
|
||||
int frames_needed_for_high_intensity;
|
||||
|
||||
int frames_to_execute; // How many frames should we execute the action for?
|
||||
};
|
||||
|
||||
void EmulateShake(NormalizedAccelData* accel, ControllerEmu::Buttons* buttons_group,
|
||||
double intensity, u8* shake_step);
|
||||
|
||||
void EmulateDynamicShake(NormalizedAccelData* accel, DynamicData& dynamic_data,
|
||||
ControllerEmu::Buttons* buttons_group, const DynamicConfiguration& config,
|
||||
u8* shake_step);
|
||||
|
||||
void EmulateTilt(NormalizedAccelData* accel, ControllerEmu::Tilt* tilt_group, bool sideways = false,
|
||||
bool upright = false);
|
||||
|
||||
void EmulateSwing(NormalizedAccelData* accel, ControllerEmu::Force* swing_group, double intensity,
|
||||
bool sideways = false, bool upright = false);
|
||||
|
||||
void EmulateDynamicSwing(NormalizedAccelData* accel, DynamicData& dynamic_data,
|
||||
ControllerEmu::Force* swing_group, const DynamicConfiguration& config,
|
||||
bool sideways = false, bool upright = false);
|
||||
|
||||
WiimoteCommon::DataReportBuilder::AccelData DenormalizeAccelData(const NormalizedAccelData& accel,
|
||||
u16 zero_g, u16 one_g);
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
File diff suppressed because it is too large
Load Diff
@@ -241,8 +241,10 @@ static void GenerateTables(const u8* const rand, const u8* const key, const u8 i
|
||||
sb[7] = sboxes[idx][rand[2]] ^ sboxes[(idx + 1) % 8][rand[6]];
|
||||
}
|
||||
|
||||
/* Generate key from the 0x40-0x4c data in g_RegExt */
|
||||
void WiimoteGenerateKey(wiimote_key* const key, const u8* const keydata)
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
// Generate key from the 0x40-0x4c data in g_RegExt
|
||||
void EncryptionKey::Generate(const u8* const keydata)
|
||||
{
|
||||
u8 rand[10];
|
||||
u8 skey[6];
|
||||
@@ -262,22 +264,24 @@ void WiimoteGenerateKey(wiimote_key* const key, const u8* const keydata)
|
||||
}
|
||||
// default case is idx = 7 which is valid (homebrew uses it for the 0x17 case)
|
||||
|
||||
GenerateTables(rand, skey, idx, key->ft, key->sb);
|
||||
GenerateTables(rand, skey, idx, ft, sb);
|
||||
|
||||
// for homebrew, ft and sb are all 0x97 which is equivalent to 0x17
|
||||
}
|
||||
|
||||
// TODO: is there a reason these can only handle a length of 255?
|
||||
/* Encrypt data */
|
||||
void WiimoteEncrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len)
|
||||
// Question: Is there a reason these can only handle a length of 255?
|
||||
// Answer: The i2c address space is only 8-bits so it really doesn't need to.
|
||||
// Also, only 21 bytes are ever encrypted at most (6 in any normal game).
|
||||
void EncryptionKey::Encrypt(u8* const data, int addr, const u8 len) const
|
||||
{
|
||||
for (int i = 0; i < len; ++i, ++addr)
|
||||
data[i] = (data[i] - key->ft[addr % 8]) ^ key->sb[addr % 8];
|
||||
data[i] = (data[i] - ft[addr % 8]) ^ sb[addr % 8];
|
||||
}
|
||||
|
||||
/* Decrypt data */
|
||||
void WiimoteDecrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len)
|
||||
void EncryptionKey::Decrypt(u8* const data, int addr, const u8 len) const
|
||||
{
|
||||
for (int i = 0; i < len; ++i, ++addr)
|
||||
data[i] = (data[i] ^ key->sb[addr % 8]) + key->ft[addr % 8];
|
||||
data[i] = (data[i] ^ sb[addr % 8]) + ft[addr % 8];
|
||||
}
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
@@ -8,14 +8,19 @@
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
// The key structure to use with WiimoteGenerateKey()
|
||||
struct wiimote_key
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
u8 ft[8];
|
||||
u8 sb[8];
|
||||
class EncryptionKey
|
||||
{
|
||||
public:
|
||||
void Generate(const u8* keydata);
|
||||
|
||||
void Encrypt(u8* data, int addr, u8 len) const;
|
||||
void Decrypt(u8* data, int addr, u8 len) const;
|
||||
|
||||
private:
|
||||
u8 ft[8] = {};
|
||||
u8 sb[8] = {};
|
||||
};
|
||||
|
||||
void WiimoteEncrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len);
|
||||
void WiimoteDecrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len);
|
||||
|
||||
void WiimoteGenerateKey(wiimote_key* const key, const u8* const keydata);
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
+44
-41
@@ -2,11 +2,12 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Attachment/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
@@ -71,7 +72,7 @@ constexpr std::array<u16, 4> classic_dpad_bitmasks{{
|
||||
Classic::PAD_RIGHT,
|
||||
}};
|
||||
|
||||
Classic::Classic(ExtensionReg& reg) : Attachment(_trans("Classic"), reg)
|
||||
Classic::Classic() : EncryptedExtension(_trans("Classic"))
|
||||
{
|
||||
// buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
@@ -104,52 +105,20 @@ Classic::Classic(ExtensionReg& reg) : Attachment(_trans("Classic"), reg)
|
||||
m_dpad->controls.emplace_back(
|
||||
new ControllerEmu::Input(ControllerEmu::Translate, named_direction));
|
||||
}
|
||||
|
||||
m_id = classic_id;
|
||||
|
||||
// Build calibration data:
|
||||
m_calibration = {{
|
||||
// Left Stick X max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Left Stick Y max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Right Stick X max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Right Stick Y max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Left/Right trigger range: (assumed based on real calibration data values)
|
||||
LEFT_TRIGGER_RANGE,
|
||||
RIGHT_TRIGGER_RANGE,
|
||||
// 2 checksum bytes calculated below:
|
||||
0x00,
|
||||
0x00,
|
||||
}};
|
||||
|
||||
UpdateCalibrationDataChecksum(m_calibration);
|
||||
}
|
||||
|
||||
void Classic::GetState(u8* const data)
|
||||
void Classic::Update()
|
||||
{
|
||||
wm_classic_extension classic_data = {};
|
||||
|
||||
// not using calibration data, o well
|
||||
DataFormat classic_data = {};
|
||||
|
||||
// left stick
|
||||
{
|
||||
const ControllerEmu::AnalogStick::StateData left_stick_state = m_left_stick->GetState();
|
||||
|
||||
classic_data.regular_data.lx = static_cast<u8>(
|
||||
Classic::LEFT_STICK_CENTER_X + (left_stick_state.x * Classic::LEFT_STICK_RADIUS));
|
||||
classic_data.regular_data.ly = static_cast<u8>(
|
||||
Classic::LEFT_STICK_CENTER_Y + (left_stick_state.y * Classic::LEFT_STICK_RADIUS));
|
||||
classic_data.lx = static_cast<u8>(Classic::LEFT_STICK_CENTER_X +
|
||||
(left_stick_state.x * Classic::LEFT_STICK_RADIUS));
|
||||
classic_data.ly = static_cast<u8>(Classic::LEFT_STICK_CENTER_Y +
|
||||
(left_stick_state.y * Classic::LEFT_STICK_RADIUS));
|
||||
}
|
||||
|
||||
// right stick
|
||||
@@ -188,7 +157,7 @@ void Classic::GetState(u8* const data)
|
||||
// flip button bits
|
||||
classic_data.bt.hex ^= 0xFFFF;
|
||||
|
||||
std::memcpy(data, &classic_data, sizeof(wm_classic_extension));
|
||||
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = classic_data;
|
||||
}
|
||||
|
||||
bool Classic::IsButtonPressed() const
|
||||
@@ -201,6 +170,40 @@ bool Classic::IsButtonPressed() const
|
||||
return buttons != 0;
|
||||
}
|
||||
|
||||
void Classic::Reset()
|
||||
{
|
||||
m_reg = {};
|
||||
m_reg.identifier = classic_id;
|
||||
|
||||
// Build calibration data:
|
||||
m_reg.calibration = {{
|
||||
// Left Stick X max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Left Stick Y max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Right Stick X max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Right Stick Y max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Left/Right trigger range: (assumed based on real calibration data values)
|
||||
LEFT_TRIGGER_RANGE,
|
||||
RIGHT_TRIGGER_RANGE,
|
||||
// 2 checksum bytes calculated below:
|
||||
0x00,
|
||||
0x00,
|
||||
}};
|
||||
|
||||
UpdateCalibrationDataChecksum(m_reg.calibration, CALIBRATION_CHECKSUM_BYTES);
|
||||
}
|
||||
|
||||
ControllerEmu::ControlGroup* Classic::GetGroup(ClassicGroup group)
|
||||
{
|
||||
switch (group)
|
||||
+66
-6
@@ -4,7 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Attachment/Attachment.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Extension.h"
|
||||
|
||||
namespace ControllerEmu
|
||||
{
|
||||
@@ -16,15 +17,74 @@ class MixedTriggers;
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
enum class ClassicGroup;
|
||||
struct ExtensionReg;
|
||||
enum class ClassicGroup
|
||||
{
|
||||
Buttons,
|
||||
Triggers,
|
||||
DPad,
|
||||
LeftStick,
|
||||
RightStick
|
||||
};
|
||||
|
||||
class Classic : public Attachment
|
||||
class Classic : public EncryptedExtension
|
||||
{
|
||||
public:
|
||||
explicit Classic(ExtensionReg& reg);
|
||||
void GetState(u8* const data) override;
|
||||
union ButtonFormat
|
||||
{
|
||||
u16 hex;
|
||||
|
||||
struct
|
||||
{
|
||||
u8 : 1;
|
||||
u8 rt : 1; // right trigger
|
||||
u8 plus : 1;
|
||||
u8 home : 1;
|
||||
u8 minus : 1;
|
||||
u8 lt : 1; // left trigger
|
||||
u8 dpad_down : 1;
|
||||
u8 dpad_right : 1;
|
||||
|
||||
u8 dpad_up : 1;
|
||||
u8 dpad_left : 1;
|
||||
u8 zr : 1;
|
||||
u8 x : 1;
|
||||
u8 a : 1;
|
||||
u8 y : 1;
|
||||
u8 b : 1;
|
||||
u8 zl : 1; // left z button
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(ButtonFormat) == 2, "Wrong size");
|
||||
|
||||
struct DataFormat
|
||||
{
|
||||
// lx/ly/lz; left joystick
|
||||
// rx/ry/rz; right joystick
|
||||
// lt; left trigger
|
||||
// rt; left trigger
|
||||
|
||||
u8 lx : 6; // byte 0
|
||||
u8 rx3 : 2;
|
||||
|
||||
u8 ly : 6; // byte 1
|
||||
u8 rx2 : 2;
|
||||
|
||||
u8 ry : 5;
|
||||
u8 lt2 : 2;
|
||||
u8 rx1 : 1;
|
||||
|
||||
u8 rt : 5;
|
||||
u8 lt1 : 3;
|
||||
|
||||
ButtonFormat bt; // byte 4, 5
|
||||
};
|
||||
static_assert(sizeof(DataFormat) == 6, "Wrong size");
|
||||
|
||||
Classic();
|
||||
|
||||
void Update() override;
|
||||
bool IsButtonPressed() const override;
|
||||
void Reset() override;
|
||||
|
||||
ControllerEmu::ControlGroup* GetGroup(ClassicGroup group);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user