Merge pull request #7674 from jordan-woyak/wiimote-emu-cleanup

WiimoteEmu: Major cleanups
This commit is contained in:
Anthony
2019-02-03 09:25:26 -08:00
committed by GitHub
67 changed files with 4472 additions and 2679 deletions
+52
View File
@@ -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
+12 -6
View File
@@ -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
+25 -13
View File
@@ -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" />
+89 -59
View File
@@ -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
+51 -14
View File
@@ -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
+213
View File
@@ -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(&reg_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(&reg_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
+104
View File
@@ -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
+264
View File
@@ -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
+66
View File
@@ -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
+14 -10
View File
@@ -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
+13 -8
View File
@@ -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
@@ -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)
@@ -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