Skip to content
Permalink
Browse files
Merge pull request #8575 from jordan-woyak/ciface-wiimotes
InputCommon: Add support for Wii Remotes in ControllerInterface
  • Loading branch information
delroth committed Feb 22, 2020
2 parents f3c89fd + 70ac9ad commit 2b6a1ee
Show file tree
Hide file tree
Showing 42 changed files with 3,310 additions and 581 deletions.
@@ -300,6 +300,12 @@ void SetBit(T& value, size_t bit_number, bool bit_value)
value &= ~(T{1} << bit_number);
}

template <size_t bit_number, typename T>
void SetBit(T& value, bool bit_value)
{
SetBit(value, bit_number, bit_value);
}

template <typename T>
class FlagBit
{
@@ -340,4 +346,15 @@ class Flags
std::underlying_type_t<T> m_hex = 0;
};

// Left-shift a value and set new LSBs to that of the supplied LSB.
// Converts a value from a N-bit range to an (N+X)-bit range. e.g. 0x101 -> 0x10111
template <typename T>
T ExpandValue(T value, size_t left_shift_amount)
{
static_assert(std::is_unsigned<T>(), "ExpandValue is only sane on unsigned types.");

return (value << left_shift_amount) |
(T(-ExtractBit<0>(value)) >> (BitSize<T>() - left_shift_amount));
}

} // namespace Common
@@ -5,6 +5,7 @@
#pragma once

#include <algorithm>
#include <cmath>
#include <vector>

#include "Common/CommonTypes.h"
@@ -93,6 +94,45 @@ struct Rectangle
}
};

template <typename T>
class RunningMean
{
public:
constexpr void Clear() { *this = {}; }

constexpr void Push(T x) { m_mean = m_mean + (x - m_mean) / ++m_count; }

constexpr size_t Count() const { return m_count; }
constexpr T Mean() const { return m_mean; }

private:
size_t m_count = 0;
T m_mean{};
};

template <typename T>
class RunningVariance
{
public:
constexpr void Clear() { *this = {}; }

constexpr void Push(T x)
{
const auto old_mean = m_running_mean.Mean();
m_running_mean.Push(x);
m_variance += (x - old_mean) * (x - m_running_mean.Mean());
}

constexpr size_t Count() const { return m_running_mean.Count(); }
constexpr T Mean() const { return m_running_mean.Mean(); }
constexpr T Variance() const { return m_variance / (Count() - 1); }
constexpr T StandardDeviation() const { return std::sqrt(Variance()); }

private:
RunningMean<T> m_running_mean;
T m_variance{};
};

} // namespace MathUtil

float MathFloatVectorSum(const std::vector<float>&);
@@ -20,6 +20,11 @@ union TVec3
TVec3() = default;
TVec3(T _x, T _y, T _z) : data{_x, _y, _z} {}

template <typename OtherT>
explicit TVec3(const TVec3<OtherT>& other) : TVec3(other.x, other.y, other.z)
{
}

TVec3 Cross(const TVec3& rhs) const
{
return {(y * rhs.z) - (rhs.y * z), (z * rhs.x) - (rhs.z * x), (x * rhs.y) - (rhs.x * y)};
@@ -98,6 +103,11 @@ TVec3<bool> operator<(const TVec3<T>& lhs, const TVec3<T>& rhs)
return lhs.Map(std::less<T>{}, rhs);
}

inline TVec3<bool> operator!(const TVec3<bool>& vec)
{
return {!vec.x, !vec.y, !vec.z};
}

template <typename T>
auto operator+(const TVec3<T>& lhs, const TVec3<T>& rhs) -> TVec3<decltype(lhs.x + rhs.x)>
{
@@ -197,6 +207,11 @@ union TVec2
TVec2() = default;
TVec2(T _x, T _y) : data{_x, _y} {}

template <typename OtherT>
explicit TVec2(const TVec2<OtherT>& other) : TVec2(other.x, other.y)
{
}

T Cross(const TVec2& rhs) const { return (x * rhs.y) - (y * rhs.x); }
T Dot(const TVec2& rhs) const { return (x * rhs.x) + (y * rhs.y); }
T LengthSquared() const { return Dot(*this); }
@@ -217,6 +232,20 @@ union TVec2
return *this;
}

TVec2& operator*=(const TVec2& rhs)
{
x *= rhs.x;
y *= rhs.y;
return *this;
}

TVec2& operator/=(const TVec2& rhs)
{
x /= rhs.x;
y /= rhs.y;
return *this;
}

TVec2& operator*=(T scalar)
{
x *= scalar;
@@ -242,6 +271,17 @@ union TVec2
};
};

template <typename T>
TVec2<bool> operator<(const TVec2<T>& lhs, const TVec2<T>& rhs)
{
return {lhs.x < rhs.x, lhs.y < rhs.y};
}

inline TVec2<bool> operator!(const TVec2<bool>& vec)
{
return {!vec.x, !vec.y};
}

template <typename T>
TVec2<T> operator+(TVec2<T> lhs, const TVec2<T>& rhs)
{
@@ -255,15 +295,27 @@ TVec2<T> operator-(TVec2<T> lhs, const TVec2<T>& rhs)
}

template <typename T>
TVec2<T> operator*(TVec2<T> lhs, T scalar)
TVec2<T> operator*(TVec2<T> lhs, const TVec2<T>& rhs)
{
return lhs *= scalar;
return lhs *= rhs;
}

template <typename T>
TVec2<T> operator/(TVec2<T> lhs, T scalar)
TVec2<T> operator/(TVec2<T> lhs, const TVec2<T>& rhs)
{
return lhs /= scalar;
return lhs /= rhs;
}

template <typename T, typename T2>
auto operator*(TVec2<T> lhs, T2 scalar)
{
return TVec2<decltype(lhs.x * scalar)>(lhs) *= scalar;
}

template <typename T, typename T2>
auto operator/(TVec2<T> lhs, T2 scalar)
{
return TVec2<decltype(lhs.x / scalar)>(lhs) /= scalar;
}

using Vec2 = TVec2<float>;
@@ -234,6 +234,7 @@ void SConfig::SaveCoreSettings(IniFile& ini)
core->Set("WiiKeyboard", m_WiiKeyboard);
core->Set("WiimoteContinuousScanning", m_WiimoteContinuousScanning);
core->Set("WiimoteEnableSpeaker", m_WiimoteEnableSpeaker);
core->Set("WiimoteControllerInterface", connect_wiimotes_for_ciface);
core->Set("RunCompareServer", bRunCompareServer);
core->Set("RunCompareClient", bRunCompareClient);
core->Set("MMU", bMMU);
@@ -511,6 +512,7 @@ void SConfig::LoadCoreSettings(IniFile& ini)
core->Get("WiiKeyboard", &m_WiiKeyboard, false);
core->Get("WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false);
core->Get("WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, false);
core->Get("WiimoteControllerInterface", &connect_wiimotes_for_ciface, false);
core->Get("RunCompareServer", &bRunCompareServer, false);
core->Get("RunCompareClient", &bRunCompareClient, false);
core->Get("MMU", &bMMU, bMMU);
@@ -72,6 +72,7 @@ struct SConfig
bool m_WiiKeyboard;
bool m_WiimoteContinuousScanning;
bool m_WiimoteEnableSpeaker;
bool connect_wiimotes_for_ciface;

// ISO folder
std::vector<std::string> m_ISOFolder;
@@ -5,6 +5,7 @@
#include <cassert>

#include "Common/BitUtils.h"
#include "Common/MathUtil.h"
#include "Core/HW/WiimoteCommon/DataReport.h"

namespace WiimoteCommon
@@ -75,40 +76,35 @@ 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;

// X has 10 bits of precision.
result->value.x = accel.x << 2;
result->value.x |= core.acc_bits & 0b11;

// Y and Z only have 9 bits of precision. (convert them to 10)
result->value.y =
Common::ExpandValue<u16>(accel.y << 1 | Common::ExtractBit<0>(core.acc_bits2), 1);
result->value.z =
Common::ExpandValue<u16>(accel.z << 1 | Common::ExtractBit<1>(core.acc_bits2), 1);
}

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;
Common::BitCastPtr<AccelMSB>(data_ptr + 2) = AccelMSB(new_accel.value / 4);

// 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);
core.acc_bits = (new_accel.value.x >> 0) & 0b11;
core.acc_bits2 = (new_accel.value.y >> 1) & 0x1;
core.acc_bits2 |= (new_accel.value.z & 0xb10);
Common::BitCastPtr<CoreData>(data_ptr) = core;
}

bool HasAccel() const override { return true; }

private:
struct AccelMSB
{
u8 x, y, z;
};
using AccelMSB = Common::TVec3<u8>;
static_assert(sizeof(AccelMSB) == 3, "Wrong size");
};

@@ -195,26 +191,28 @@ 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;
// X axis only has 8 bits of precision. (converted to 10)
accel->value.x = Common::ExpandValue<u16>(data_ptr[2], 2);

// Y axis is not contained in this report. (provided by "Interleave2")

// Retain lower 6 bits.
accel->z &= 0b111111;
// Clear upper bits, retain lower bits. (provided by "Interleave2")
accel->value.z &= 0b111111;

// Report only contains 4 MSB of Z axis.
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
accel->z |= (core.acc_bits << 6) | (core.acc_bits2 << 8);
accel->value.z |= (core.acc_bits << 6) | (core.acc_bits2 << 8);
}

void SetAccelData(const AccelData& accel) override
{
data_ptr[2] = accel.x >> 2;
data_ptr[2] = accel.value.x >> 2;

CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
core.acc_bits = (accel.z >> 6) & 0b11;
core.acc_bits2 = (accel.z >> 8) & 0b11;
core.acc_bits = (accel.value.z >> 6) & 0b11;
core.acc_bits2 = (accel.value.z >> 8) & 0b11;
Common::BitCastPtr<CoreData>(data_ptr) = core;
}

@@ -226,26 +224,28 @@ struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt
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;
// X axis is not contained in this report. (provided by "Interleave1")

// Y axis only has 8 bits of precision. (converted to 10)
accel->value.y = Common::ExpandValue<u16>(data_ptr[2], 2);

// Retain upper 4 bits.
accel->z &= ~0b111111;
// Clear lower bits, retain upper bits. (provided by "Interleave1")
accel->value.z &= ~0b111111;

// Report only contains 4 LSBs of Z axis. (converted to 6)
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
accel->z |= (core.acc_bits << 2) | (core.acc_bits2 << 4);
accel->value.z |= Common::ExpandValue<u16>(core.acc_bits | core.acc_bits2 << 2, 2);
}

void SetAccelData(const AccelData& accel) override
{
data_ptr[2] = accel.y >> 2;
data_ptr[2] = accel.value.y >> 2;

CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
core.acc_bits = (accel.z >> 2) & 0b11;
core.acc_bits2 = (accel.z >> 4) & 0b11;
core.acc_bits = (accel.value.z >> 2) & 0b11;
core.acc_bits2 = (accel.value.z >> 4) & 0b11;
Common::BitCastPtr<CoreData>(data_ptr) = core;
}

@@ -8,9 +8,11 @@
#include <memory>

#include "Common/CommonTypes.h"
#include "Common/Matrix.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h"

namespace WiimoteCommon
{
@@ -21,12 +23,6 @@ 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;
@@ -66,7 +62,6 @@ class DataReportBuilder
explicit DataReportBuilder(InputReportID rpt_id);

using CoreData = ButtonData;
using AccelData = DataReportManipulator::AccelData;

void SetMode(InputReportID rpt_id);
InputReportID GetMode() const;
@@ -99,11 +94,10 @@ class DataReportBuilder

u32 GetDataSize() const;

private:
static constexpr int HEADER_SIZE = 2;

static constexpr int MAX_DATA_SIZE = MAX_PAYLOAD - 2;

private:
TypedHIDInputData<std::array<u8, MAX_DATA_SIZE>> m_data;

std::unique_ptr<DataReportManipulator> m_manip;

0 comments on commit 2b6a1ee

Please sign in to comment.