Skip to content

Commit

Permalink
WiimoteEmu: Implement uDraw GameTablet.
Browse files Browse the repository at this point in the history
  • Loading branch information
jordan-woyak committed Mar 13, 2019
1 parent 7944a05 commit e55733b
Show file tree
Hide file tree
Showing 27 changed files with 836 additions and 267 deletions.
1 change: 1 addition & 0 deletions Source/Core/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ add_library(core
HW/WiimoteEmu/Extension/Drums.cpp
HW/WiimoteEmu/Extension/Guitar.cpp
HW/WiimoteEmu/Extension/Turntable.cpp
HW/WiimoteEmu/Extension/UDrawTablet.cpp
HW/WiimoteReal/WiimoteReal.cpp
HW/WiiSave.cpp
IOS/Device.cpp
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Core/Core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
<ClCompile Include="HW\WiimoteEmu\Extension\Guitar.cpp" />
<ClCompile Include="HW\WiimoteEmu\Extension\Nunchuk.cpp" />
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp" />
<ClInclude Include="HW\WiimoteEmu\Extension\UDrawTablet.cpp" />
<ClCompile Include="HW\WiimoteEmu\I2CBus.cpp" />
<ClCompile Include="HW\WiimoteEmu\MotionPlus.cpp" />
<ClCompile Include="HW\WiimoteEmu\Speaker.cpp" />
Expand Down Expand Up @@ -450,6 +451,7 @@
<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\Extension\UDrawTablet.h" />
<ClInclude Include="HW\WiimoteEmu\I2CBus.h" />
<ClInclude Include="HW\WiimoteEmu\MotionPlus.h" />
<ClInclude Include="HW\WiimoteEmu\Speaker.h" />
Expand Down
8 changes: 7 additions & 1 deletion Source/Core/Core/Core.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,9 @@
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClCompile>
<ClCompile Include="HW\WiimoteEmu\Extension\UDrawTablet.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>
Expand Down Expand Up @@ -1625,6 +1628,9 @@
<ClInclude Include="HW\WiimoteEmu\Extension\Turntable.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClInclude>
<ClInclude Include="HW\WiimoteEmu\Extension\UDrawTablet.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>
Expand All @@ -1638,4 +1644,4 @@
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
</Project>
</Project>
6 changes: 6 additions & 0 deletions Source/Core/Core/HW/Wiimote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ ControllerEmu::ControlGroup* GetTurntableGroup(int number, WiimoteEmu::Turntable
->GetTurntableGroup(group);
}

ControllerEmu::ControlGroup* GetUDrawTabletGroup(int number, WiimoteEmu::UDrawTabletGroup group)
{
return static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number))
->GetUDrawTabletGroup(group);
}

void Shutdown()
{
s_config.UnregisterHotplugCallback();
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Core/HW/Wiimote.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum class ClassicGroup;
enum class GuitarGroup;
enum class DrumsGroup;
enum class TurntableGroup;
enum class UDrawTabletGroup;
} // namespace WiimoteEmu

enum
Expand Down Expand Up @@ -75,6 +76,7 @@ ControllerEmu::ControlGroup* GetClassicGroup(int number, WiimoteEmu::ClassicGrou
ControllerEmu::ControlGroup* GetGuitarGroup(int number, WiimoteEmu::GuitarGroup group);
ControllerEmu::ControlGroup* GetDrumsGroup(int number, WiimoteEmu::DrumsGroup group);
ControllerEmu::ControlGroup* GetTurntableGroup(int number, WiimoteEmu::TurntableGroup group);
ControllerEmu::ControlGroup* GetUDrawTabletGroup(int number, WiimoteEmu::UDrawTabletGroup group);

void ControlChannel(int number, u16 channel_id, const void* data, u32 size);
void InterruptChannel(int number, u16 channel_id, const void* data, u32 size);
Expand Down
682 changes: 452 additions & 230 deletions Source/Core/Core/HW/WiimoteEmu/Encryption.cpp

Large diffs are not rendered by default.

41 changes: 36 additions & 5 deletions Source/Core/Core/HW/WiimoteEmu/Encryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,52 @@

#pragma once

#include <array>

#include "Common/CommonTypes.h"

namespace WiimoteEmu
{
class EncryptionKey
{
public:
void Generate(const u8* keydata);
void Encrypt(u8* data, u32 addr, u32 len) const;
void Decrypt(u8* data, u32 addr, u32 len) const;

void GenerateTables(const std::array<u8, 10>& rand, const std::array<u8, 6>& key, const u8 idx,
const u8 offset);

std::array<u8, 8> ft = {};
std::array<u8, 8> sb = {};
};

class KeyGen
{
public:
virtual ~KeyGen() = default;

void Encrypt(u8* data, int addr, u8 len) const;
void Decrypt(u8* data, int addr, u8 len) const;
EncryptionKey GenerateFromExtensionKeyData(const std::array<u8, 0x10>& key_data) const;

protected:
virtual std::array<u8, 6> GenerateKey(const std::array<u8, 10>& rand, const u8 idx) const = 0;
virtual EncryptionKey GenerateTables(const std::array<u8, 10>& rand, const std::array<u8, 6>& key,
u8 idx) const = 0;
};

class KeyGen1stParty final : public KeyGen
{
private:
std::array<u8, 6> GenerateKey(const std::array<u8, 10>& rand, const u8 idx) const final override;
EncryptionKey GenerateTables(const std::array<u8, 10>& rand, const std::array<u8, 6>& key,
u8 idx) const final override;
};

class KeyGen3rdParty final : public KeyGen
{
private:
u8 ft[8] = {};
u8 sb[8] = {};
std::array<u8, 6> GenerateKey(const std::array<u8, 10>& rand, const u8 idx) const final override;
EncryptionKey GenerateTables(const std::array<u8, 10>& rand, const std::array<u8, 6>& key,
u8 idx) const final override;
};

} // namespace WiimoteEmu
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ constexpr std::array<u16, 4> classic_dpad_bitmasks{{
Classic::PAD_RIGHT,
}};

Classic::Classic() : EncryptedExtension(_trans("Classic"))
Classic::Classic() : Extension1stParty(_trans("Classic"))
{
// buttons
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ enum class ClassicGroup
RightStick
};

class Classic : public EncryptedExtension
class Classic : public Extension1stParty
{
public:
union ButtonFormat
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/WiimoteEmu/Extension/Drums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ constexpr std::array<u16, 2> drum_button_bitmasks{{
Drums::BUTTON_PLUS,
}};

Drums::Drums() : EncryptedExtension(_trans("Drums"))
Drums::Drums() : Extension1stParty(_trans("Drums"))
{
// pads
groups.emplace_back(m_pads = new ControllerEmu::Buttons(_trans("Pads")));
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/WiimoteEmu/Extension/Drums.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ enum class DrumsGroup
Stick
};

// TODO: Do the drums ever use encryption?
class Drums : public EncryptedExtension
// The Guitar uses the "1st-party" extension encryption scheme.
class Drums : public Extension1stParty
{
public:
struct DataFormat
Expand Down
48 changes: 34 additions & 14 deletions Source/Core/Core/HW/WiimoteEmu/Extension/Extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "Common/Compiler.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"

#include "Common/Logging/Log.h"

namespace WiimoteEmu
{
Extension::Extension(const char* name) : m_name(name)
Expand Down Expand Up @@ -85,15 +87,10 @@ int EncryptedExtension::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)

auto const result = RawRead(&m_reg, addr, count, data_out);

// Encrypt data read from extension register
// Encrypt data read from extension register.
if (ENCRYPTION_ENABLED == m_reg.encryption)
{
// INFO_LOG(WIIMOTE, "Encrypted read.");
ext_key.Encrypt(data_out, addr, (u8)count);
}
else
{
// INFO_LOG(WIIMOTE, "Unencrypted read.");
ext_key.Encrypt(data_out, addr, count);
}

return result;
Expand All @@ -106,12 +103,15 @@ int EncryptedExtension::BusWrite(u8 slave_addr, u8 addr, int count, const u8* da

auto const result = RawWrite(&m_reg, addr, count, data_in);

// TODO: make this check less ugly:
if (addr + count > 0x40 && addr < 0x50)
constexpr u8 ENCRYPTION_KEY_DATA_BEGIN = offsetof(Register, encryption_key_data);
constexpr u8 ENCRYPTION_KEY_DATA_END = ENCRYPTION_KEY_DATA_BEGIN + 0x10;

if (addr + count > ENCRYPTION_KEY_DATA_BEGIN && addr < ENCRYPTION_KEY_DATA_END)
{
// Run the key generation on all writes in the key area, it doesn't matter
// that we send it parts of a key, only the last full key will have an effect
ext_key.Generate(m_reg.encryption_key_data);
// FYI: Real extensions seem to require the key data written in specifically sized chunks.
// We just run the key generation on all writes to the key area, it doesn't matter
// that we send it incomplete data, only the last full key will have an effect
UpdateEncryptionKey();
}

return result;
Expand All @@ -121,9 +121,29 @@ void EncryptedExtension::DoState(PointerWrap& p)
{
p.Do(m_reg);

// No need to sync this when we can regenerate it:
if (p.GetMode() == PointerWrap::MODE_READ)
ext_key.Generate(m_reg.encryption_key_data);
{
// No need to sync the key when we can just regenerate it.
UpdateEncryptionKey();
}
}

Extension1stParty::Extension1stParty(const char* name) : EncryptedExtension(name)
{
}

Extension3rdParty::Extension3rdParty(const char* name) : EncryptedExtension(name)
{
}

void Extension1stParty::UpdateEncryptionKey()
{
ext_key = KeyGen1stParty().GenerateFromExtensionKeyData(m_reg.encryption_key_data);
}

void Extension3rdParty::UpdateEncryptionKey()
{
ext_key = KeyGen3rdParty().GenerateFromExtensionKeyData(m_reg.encryption_key_data);
}

} // namespace WiimoteEmu
24 changes: 22 additions & 2 deletions Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class EncryptedExtension : public Extension

// TODO: This is public for TAS reasons.
// TODO: TAS handles encryption poorly.
WiimoteEmu::EncryptionKey ext_key = {};
EncryptionKey ext_key;

protected:
static constexpr int CALIBRATION_CHECKSUM_BYTES = 2;
Expand All @@ -82,7 +82,7 @@ class EncryptedExtension : public Extension
u8 unknown3[0x10];

// address 0x40
u8 encryption_key_data[0x10];
std::array<u8, 0x10> encryption_key_data;
u8 unknown4[0xA0];

// address 0xF0
Expand All @@ -100,6 +100,8 @@ class EncryptedExtension : public Extension

void DoState(PointerWrap& p) override;

virtual void UpdateEncryptionKey() = 0;

private:
static constexpr u8 ENCRYPTION_ENABLED = 0xaa;

Expand All @@ -109,4 +111,22 @@ class EncryptedExtension : public Extension
int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) override;
};

class Extension1stParty : public EncryptedExtension
{
protected:
Extension1stParty(const char* name);

private:
void UpdateEncryptionKey() final override;
};

class Extension3rdParty : public EncryptedExtension
{
protected:
Extension3rdParty(const char* name);

private:
void UpdateEncryptionKey() final override;
};

} // namespace WiimoteEmu
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ constexpr std::array<u16, 2> guitar_strum_bitmasks{{
Guitar::BAR_DOWN,
}};

Guitar::Guitar() : EncryptedExtension(_trans("Guitar"))
Guitar::Guitar() : Extension1stParty(_trans("Guitar"))
{
// frets
groups.emplace_back(m_frets = new ControllerEmu::Buttons(_trans("Frets")));
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ enum class GuitarGroup
SliderBar
};

// TODO: Does the guitar ever use encryption?
class Guitar : public EncryptedExtension
// The Guitar uses the "1st-party" extension encryption scheme.
class Guitar : public Extension1stParty
{
public:
struct DataFormat
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ constexpr std::array<u8, 2> nunchuk_button_bitmasks{{
Nunchuk::BUTTON_Z,
}};

Nunchuk::Nunchuk() : EncryptedExtension(_trans("Nunchuk"))
Nunchuk::Nunchuk() : Extension1stParty(_trans("Nunchuk"))
{
// buttons
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ enum class NunchukGroup
Shake
};

class Nunchuk : public EncryptedExtension
class Nunchuk : public Extension1stParty
{
public:
union ButtonFormat
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ constexpr std::array<const char*, 6> turntable_button_names{{
_trans("Blue Right"),
}};

Turntable::Turntable() : EncryptedExtension(_trans("Turntable"))
Turntable::Turntable() : Extension1stParty(_trans("Turntable"))
{
// buttons
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ enum class TurntableGroup
Crossfade
};

// TODO: Does the turntable ever use encryption?
class Turntable : public EncryptedExtension
// The DJ Hero Turntable uses the "1st-party" extension encryption scheme.
class Turntable : public Extension1stParty
{
public:
struct DataFormat
Expand Down
Loading

0 comments on commit e55733b

Please sign in to comment.