WiimoteEmu: Code cleanups.
This commit is contained in:
parent
3945aa6242
commit
9c1a8891e5
|
@ -200,13 +200,55 @@ inline To BitCast(const From& source) noexcept
|
||||||
return reinterpret_cast<To&>(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>
|
template <typename T>
|
||||||
void SetBit(T& value, size_t bit_number, bool bit_value)
|
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)
|
if (bit_value)
|
||||||
value |= (1 << bit_number);
|
value |= (T{1} << bit_number);
|
||||||
else
|
else
|
||||||
value &= ~(1 << bit_number);
|
value &= ~(T{1} << bit_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Core/HW/WiimoteCommon/DataReport.h"
|
#include "Core/HW/WiimoteCommon/DataReport.h"
|
||||||
|
|
||||||
namespace WiimoteCommon
|
namespace WiimoteCommon
|
||||||
|
@ -34,7 +35,7 @@ struct IncludeCore : virtual DataReportManipulator
|
||||||
|
|
||||||
void GetCoreData(CoreData* result) const override
|
void GetCoreData(CoreData* result) const override
|
||||||
{
|
{
|
||||||
*result = *reinterpret_cast<const CoreData*>(data_ptr);
|
*result = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
|
|
||||||
// Remove accel LSBs.
|
// Remove accel LSBs.
|
||||||
result->hex &= CoreData::BUTTON_MASK;
|
result->hex &= CoreData::BUTTON_MASK;
|
||||||
|
@ -42,11 +43,13 @@ struct IncludeCore : virtual DataReportManipulator
|
||||||
|
|
||||||
void SetCoreData(const CoreData& new_core) override
|
void SetCoreData(const CoreData& new_core) override
|
||||||
{
|
{
|
||||||
auto& core = *reinterpret_cast<CoreData*>(data_ptr);
|
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
|
|
||||||
// Don't overwrite accel LSBs.
|
// Don't overwrite accel LSBs.
|
||||||
core.hex &= ~CoreData::BUTTON_MASK;
|
core.hex &= ~CoreData::BUTTON_MASK;
|
||||||
core.hex |= new_core.hex & CoreData::BUTTON_MASK;
|
core.hex |= new_core.hex & CoreData::BUTTON_MASK;
|
||||||
|
|
||||||
|
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,13 +74,13 @@ struct IncludeAccel : virtual DataReportManipulator
|
||||||
{
|
{
|
||||||
void GetAccelData(AccelData* result) const override
|
void GetAccelData(AccelData* result) const override
|
||||||
{
|
{
|
||||||
const auto& accel = *reinterpret_cast<AccelMSB*>(data_ptr + 2);
|
const AccelMSB accel = Common::BitCastPtr<AccelMSB>(data_ptr + 2);
|
||||||
result->x = accel.x << 2;
|
result->x = accel.x << 2;
|
||||||
result->y = accel.y << 2;
|
result->y = accel.y << 2;
|
||||||
result->z = accel.z << 2;
|
result->z = accel.z << 2;
|
||||||
|
|
||||||
// LSBs
|
// LSBs
|
||||||
const auto& core = *reinterpret_cast<CoreData*>(data_ptr);
|
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
result->x |= core.acc_bits & 0b11;
|
result->x |= core.acc_bits & 0b11;
|
||||||
result->y |= (core.acc_bits2 & 0b1) << 1;
|
result->y |= (core.acc_bits2 & 0b1) << 1;
|
||||||
result->z |= core.acc_bits2 & 0b10;
|
result->z |= core.acc_bits2 & 0b10;
|
||||||
|
@ -85,16 +88,18 @@ struct IncludeAccel : virtual DataReportManipulator
|
||||||
|
|
||||||
void SetAccelData(const AccelData& new_accel) override
|
void SetAccelData(const AccelData& new_accel) override
|
||||||
{
|
{
|
||||||
auto& accel = *reinterpret_cast<AccelMSB*>(data_ptr + 2);
|
AccelMSB accel = {};
|
||||||
accel.x = new_accel.x >> 2;
|
accel.x = new_accel.x >> 2;
|
||||||
accel.y = new_accel.y >> 2;
|
accel.y = new_accel.y >> 2;
|
||||||
accel.z = new_accel.z >> 2;
|
accel.z = new_accel.z >> 2;
|
||||||
|
Common::BitCastPtr<AccelMSB>(data_ptr + 2) = accel;
|
||||||
|
|
||||||
// LSBs
|
// LSBs
|
||||||
auto& core = *reinterpret_cast<CoreData*>(data_ptr);
|
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
core.acc_bits = (new_accel.x >> 0) & 0b11;
|
core.acc_bits = (new_accel.x >> 0) & 0b11;
|
||||||
core.acc_bits2 = (new_accel.y >> 1) & 0x1;
|
core.acc_bits2 = (new_accel.y >> 1) & 0x1;
|
||||||
core.acc_bits2 |= (new_accel.z & 0xb10);
|
core.acc_bits2 |= (new_accel.z & 0xb10);
|
||||||
|
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasAccel() const override { return true; }
|
bool HasAccel() const override { return true; }
|
||||||
|
@ -196,10 +201,10 @@ struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt
|
||||||
{
|
{
|
||||||
accel->x = data_ptr[2] << 2;
|
accel->x = data_ptr[2] << 2;
|
||||||
|
|
||||||
// Retain lower 6LSBs.
|
// Retain lower 6 bits.
|
||||||
accel->z &= 0b111111;
|
accel->z &= 0b111111;
|
||||||
|
|
||||||
const auto& core = *reinterpret_cast<CoreData*>(data_ptr);
|
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
accel->z |= (core.acc_bits << 6) | (core.acc_bits2 << 8);
|
accel->z |= (core.acc_bits << 6) | (core.acc_bits2 << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +212,10 @@ struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt
|
||||||
{
|
{
|
||||||
data_ptr[2] = accel.x >> 2;
|
data_ptr[2] = accel.x >> 2;
|
||||||
|
|
||||||
auto& core = *reinterpret_cast<CoreData*>(data_ptr);
|
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
core.acc_bits = (accel.z >> 6) & 0b11;
|
core.acc_bits = (accel.z >> 6) & 0b11;
|
||||||
core.acc_bits2 = (accel.z >> 8) & 0b11;
|
core.acc_bits2 = (accel.z >> 8) & 0b11;
|
||||||
|
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasAccel() const override { return true; }
|
bool HasAccel() const override { return true; }
|
||||||
|
@ -226,10 +232,10 @@ struct ReportInterleave2 : IncludeCore, IncludeIR<3, 18, 18>, NoExt
|
||||||
{
|
{
|
||||||
accel->y = data_ptr[2] << 2;
|
accel->y = data_ptr[2] << 2;
|
||||||
|
|
||||||
// Retain upper 4MSBs.
|
// Retain upper 4 bits.
|
||||||
accel->z &= ~0b111111;
|
accel->z &= ~0b111111;
|
||||||
|
|
||||||
const auto& core = *reinterpret_cast<CoreData*>(data_ptr);
|
const CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
accel->z |= (core.acc_bits << 2) | (core.acc_bits2 << 4);
|
accel->z |= (core.acc_bits << 2) | (core.acc_bits2 << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,9 +243,10 @@ struct ReportInterleave2 : IncludeCore, IncludeIR<3, 18, 18>, NoExt
|
||||||
{
|
{
|
||||||
data_ptr[2] = accel.y >> 2;
|
data_ptr[2] = accel.y >> 2;
|
||||||
|
|
||||||
auto& core = *reinterpret_cast<CoreData*>(data_ptr);
|
CoreData core = Common::BitCastPtr<CoreData>(data_ptr);
|
||||||
core.acc_bits = (accel.z >> 2) & 0b11;
|
core.acc_bits = (accel.z >> 2) & 0b11;
|
||||||
core.acc_bits2 = (accel.z >> 4) & 0b11;
|
core.acc_bits2 = (accel.z >> 4) & 0b11;
|
||||||
|
Common::BitCastPtr<CoreData>(data_ptr) = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasAccel() const override { return true; }
|
bool HasAccel() const override { return true; }
|
||||||
|
@ -257,47 +264,47 @@ std::unique_ptr<DataReportManipulator> MakeDataReportManipulator(InputReportID r
|
||||||
|
|
||||||
switch (rpt_id)
|
switch (rpt_id)
|
||||||
{
|
{
|
||||||
case InputReportID::REPORT_CORE:
|
case InputReportID::ReportCore:
|
||||||
// 0x30: Core Buttons
|
// 0x30: Core Buttons
|
||||||
ptr = std::make_unique<ReportCore>();
|
ptr = std::make_unique<ReportCore>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_CORE_ACCEL:
|
case InputReportID::ReportCoreAccel:
|
||||||
// 0x31: Core Buttons and Accelerometer
|
// 0x31: Core Buttons and Accelerometer
|
||||||
ptr = std::make_unique<ReportCoreAccel>();
|
ptr = std::make_unique<ReportCoreAccel>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_CORE_EXT8:
|
case InputReportID::ReportCoreExt8:
|
||||||
// 0x32: Core Buttons with 8 Extension bytes
|
// 0x32: Core Buttons with 8 Extension bytes
|
||||||
ptr = std::make_unique<ReportCoreExt8>();
|
ptr = std::make_unique<ReportCoreExt8>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_CORE_ACCEL_IR12:
|
case InputReportID::ReportCoreAccelIR12:
|
||||||
// 0x33: Core Buttons and Accelerometer with 12 IR bytes
|
// 0x33: Core Buttons and Accelerometer with 12 IR bytes
|
||||||
ptr = std::make_unique<ReportCoreAccelIR12>();
|
ptr = std::make_unique<ReportCoreAccelIR12>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_CORE_EXT19:
|
case InputReportID::ReportCoreExt19:
|
||||||
// 0x34: Core Buttons with 19 Extension bytes
|
// 0x34: Core Buttons with 19 Extension bytes
|
||||||
ptr = std::make_unique<ReportCoreExt19>();
|
ptr = std::make_unique<ReportCoreExt19>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_CORE_ACCEL_EXT16:
|
case InputReportID::ReportCoreAccelExt16:
|
||||||
// 0x35: Core Buttons and Accelerometer with 16 Extension Bytes
|
// 0x35: Core Buttons and Accelerometer with 16 Extension Bytes
|
||||||
ptr = std::make_unique<ReportCoreAccelExt16>();
|
ptr = std::make_unique<ReportCoreAccelExt16>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_CORE_IR10_EXT9:
|
case InputReportID::ReportCoreIR10Ext9:
|
||||||
// 0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes
|
// 0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes
|
||||||
ptr = std::make_unique<ReportCoreIR10Ext9>();
|
ptr = std::make_unique<ReportCoreIR10Ext9>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_CORE_ACCEL_IR10_EXT6:
|
case InputReportID::ReportCoreAccelIR10Ext6:
|
||||||
// 0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes
|
// 0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes
|
||||||
ptr = std::make_unique<ReportCoreAccelIR10Ext6>();
|
ptr = std::make_unique<ReportCoreAccelIR10Ext6>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_EXT21:
|
case InputReportID::ReportExt21:
|
||||||
// 0x3d: 21 Extension Bytes
|
// 0x3d: 21 Extension Bytes
|
||||||
ptr = std::make_unique<ReportExt21>();
|
ptr = std::make_unique<ReportExt21>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_INTERLEAVE1:
|
case InputReportID::ReportInterleave1:
|
||||||
// 0x3e - 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
|
// 0x3e - 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
|
||||||
ptr = std::make_unique<ReportInterleave1>();
|
ptr = std::make_unique<ReportInterleave1>();
|
||||||
break;
|
break;
|
||||||
case InputReportID::REPORT_INTERLEAVE2:
|
case InputReportID::ReportInterleave2:
|
||||||
ptr = std::make_unique<ReportInterleave2>();
|
ptr = std::make_unique<ReportInterleave2>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -327,9 +334,8 @@ InputReportID DataReportBuilder::GetMode() const
|
||||||
|
|
||||||
bool DataReportBuilder::IsValidMode(InputReportID mode)
|
bool DataReportBuilder::IsValidMode(InputReportID mode)
|
||||||
{
|
{
|
||||||
return (mode >= InputReportID::REPORT_CORE &&
|
return (mode >= InputReportID::ReportCore && mode <= InputReportID::ReportCoreAccelIR10Ext6) ||
|
||||||
mode <= InputReportID::REPORT_CORE_ACCEL_IR10_EXT6) ||
|
(mode >= InputReportID::ReportExt21 && InputReportID::ReportInterleave2 <= mode);
|
||||||
(mode >= InputReportID::REPORT_EXT21 && InputReportID::REPORT_INTERLEAVE2 <= mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataReportBuilder::HasCore() const
|
bool DataReportBuilder::HasCore() const
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
u16 x, y, z;
|
u16 x, y, z;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ButtonData CoreData;
|
using CoreData = ButtonData;
|
||||||
|
|
||||||
virtual bool HasCore() const = 0;
|
virtual bool HasCore() const = 0;
|
||||||
virtual bool HasAccel() const = 0;
|
virtual bool HasAccel() const = 0;
|
||||||
|
@ -63,13 +63,10 @@ std::unique_ptr<DataReportManipulator> MakeDataReportManipulator(InputReportID r
|
||||||
class DataReportBuilder
|
class DataReportBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DataReportBuilder(InputReportID rpt_id);
|
explicit DataReportBuilder(InputReportID rpt_id);
|
||||||
|
|
||||||
typedef ButtonData CoreData;
|
using CoreData = ButtonData;
|
||||||
typedef DataReportManipulator::AccelData AccelData;
|
using AccelData = DataReportManipulator::AccelData;
|
||||||
|
|
||||||
typedef std::vector<u8> IRData;
|
|
||||||
typedef std::vector<u8> ExtData;
|
|
||||||
|
|
||||||
void SetMode(InputReportID rpt_id);
|
void SetMode(InputReportID rpt_id);
|
||||||
InputReportID GetMode() const;
|
InputReportID GetMode() const;
|
||||||
|
|
|
@ -12,45 +12,45 @@ constexpr u8 MAX_PAYLOAD = 23;
|
||||||
|
|
||||||
enum class InputReportID : u8
|
enum class InputReportID : u8
|
||||||
{
|
{
|
||||||
STATUS = 0x20,
|
Status = 0x20,
|
||||||
READ_DATA_REPLY = 0x21,
|
ReadDataReply = 0x21,
|
||||||
ACK = 0x22,
|
Ack = 0x22,
|
||||||
|
|
||||||
// Not a real value on the wiimote, just a state to disable reports:
|
// Not a real value on the wiimote, just a state to disable reports:
|
||||||
REPORT_DISABLED = 0x00,
|
ReportDisabled = 0x00,
|
||||||
|
|
||||||
REPORT_CORE = 0x30,
|
ReportCore = 0x30,
|
||||||
REPORT_CORE_ACCEL = 0x31,
|
ReportCoreAccel = 0x31,
|
||||||
REPORT_CORE_EXT8 = 0x32,
|
ReportCoreExt8 = 0x32,
|
||||||
REPORT_CORE_ACCEL_IR12 = 0x33,
|
ReportCoreAccelIR12 = 0x33,
|
||||||
REPORT_CORE_EXT19 = 0x34,
|
ReportCoreExt19 = 0x34,
|
||||||
REPORT_CORE_ACCEL_EXT16 = 0x35,
|
ReportCoreAccelExt16 = 0x35,
|
||||||
REPORT_CORE_IR10_EXT9 = 0x36,
|
ReportCoreIR10Ext9 = 0x36,
|
||||||
REPORT_CORE_ACCEL_IR10_EXT6 = 0x37,
|
ReportCoreAccelIR10Ext6 = 0x37,
|
||||||
|
|
||||||
REPORT_EXT21 = 0x3d,
|
ReportExt21 = 0x3d,
|
||||||
REPORT_INTERLEAVE1 = 0x3e,
|
ReportInterleave1 = 0x3e,
|
||||||
REPORT_INTERLEAVE2 = 0x3f,
|
ReportInterleave2 = 0x3f,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OutputReportID : u8
|
enum class OutputReportID : u8
|
||||||
{
|
{
|
||||||
RUMBLE = 0x10,
|
Rumble = 0x10,
|
||||||
LEDS = 0x11,
|
LED = 0x11,
|
||||||
REPORT_MODE = 0x12,
|
ReportMode = 0x12,
|
||||||
IR_PIXEL_CLOCK = 0x13,
|
IRPixelClock = 0x13,
|
||||||
SPEAKER_ENABLE = 0x14,
|
SpeakerEnable = 0x14,
|
||||||
REQUEST_STATUS = 0x15,
|
RequestStatus = 0x15,
|
||||||
WRITE_DATA = 0x16,
|
WriteData = 0x16,
|
||||||
READ_DATA = 0x17,
|
ReadData = 0x17,
|
||||||
SPEAKER_DATA = 0x18,
|
SpeakerData = 0x18,
|
||||||
SPEAKER_MUTE = 0x19,
|
SpeakerMute = 0x19,
|
||||||
IR_LOGIC = 0x1A,
|
IRLogic = 0x1a,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LED : u8
|
enum class LED : u8
|
||||||
{
|
{
|
||||||
NONE = 0x00,
|
None = 0x00,
|
||||||
LED_1 = 0x10,
|
LED_1 = 0x10,
|
||||||
LED_2 = 0x20,
|
LED_2 = 0x20,
|
||||||
LED_3 = 0x40,
|
LED_3 = 0x40,
|
||||||
|
@ -63,19 +63,16 @@ enum class AddressSpace : u8
|
||||||
// However attempting to access this device directly results in an error.
|
// However attempting to access this device directly results in an error.
|
||||||
EEPROM = 0x00,
|
EEPROM = 0x00,
|
||||||
// 0x01 is never used but it does function on a real wiimote:
|
// 0x01 is never used but it does function on a real wiimote:
|
||||||
I2C_BUS_ALT = 0x01,
|
I2CBusAlt = 0x01,
|
||||||
I2C_BUS = 0x02,
|
I2CBus = 0x02,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ErrorCode : u8
|
enum class ErrorCode : u8
|
||||||
{
|
{
|
||||||
SUCCESS = 0,
|
Success = 0,
|
||||||
INVALID_SPACE = 6,
|
InvalidSpace = 6,
|
||||||
NACK = 7,
|
Nack = 7,
|
||||||
INVALID_ADDRESS = 8,
|
InvalidAddress = 8,
|
||||||
|
|
||||||
// Not a real value:
|
|
||||||
DO_NOT_SEND_ACK = 0xff,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace WiimoteCommon
|
} // namespace WiimoteCommon
|
||||||
|
|
|
@ -54,7 +54,7 @@ struct TypedHIDInputData
|
||||||
|
|
||||||
T data;
|
T data;
|
||||||
|
|
||||||
static_assert(std::is_pod<T>::value);
|
static_assert(std::is_pod<T>());
|
||||||
|
|
||||||
u8* GetData() { return reinterpret_cast<u8*>(this); }
|
u8* GetData() { return reinterpret_cast<u8*>(this); }
|
||||||
const u8* GetData() const { return reinterpret_cast<const u8*>(this); }
|
const u8* GetData() const { return reinterpret_cast<const u8*>(this); }
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "Core/HW/WiimoteEmu/Camera.h"
|
#include "Core/HW/WiimoteEmu/Camera.h"
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||||
#include "Core/HW/WiimoteEmu/MatrixMath.h"
|
#include "Core/HW/WiimoteEmu/MatrixMath.h"
|
||||||
|
@ -39,9 +40,6 @@ int CameraLogic::BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in)
|
||||||
void CameraLogic::Update(const ControllerEmu::Cursor::StateData& cursor,
|
void CameraLogic::Update(const ControllerEmu::Cursor::StateData& cursor,
|
||||||
const NormalizedAccelData& accel, bool sensor_bar_on_top)
|
const NormalizedAccelData& accel, bool sensor_bar_on_top)
|
||||||
{
|
{
|
||||||
u16 x[4], y[4];
|
|
||||||
memset(x, 0xFF, sizeof(x));
|
|
||||||
|
|
||||||
double nsin, ncos;
|
double nsin, ncos;
|
||||||
|
|
||||||
// Ugly code to figure out the wiimote's current angle.
|
// Ugly code to figure out the wiimote's current angle.
|
||||||
|
@ -73,7 +71,10 @@ void CameraLogic::Update(const ControllerEmu::Cursor::StateData& cursor,
|
||||||
static constexpr double dist1 = 100.0 / camWidth; // this seems the optimal distance for zelda
|
static constexpr double dist1 = 100.0 / camWidth; // this seems the optimal distance for zelda
|
||||||
static constexpr double dist2 = 1.2 * dist1;
|
static constexpr double dist2 = 1.2 * dist1;
|
||||||
|
|
||||||
std::array<Vertex, 4> v;
|
constexpr int NUM_POINTS = 4;
|
||||||
|
|
||||||
|
std::array<Vertex, NUM_POINTS> v;
|
||||||
|
|
||||||
for (auto& vtx : v)
|
for (auto& vtx : v)
|
||||||
{
|
{
|
||||||
vtx.x = cursor.x * (bndright - bndleft) / 2 + (bndleft + bndright) / 2;
|
vtx.x = cursor.x * (bndright - bndleft) / 2 + (bndleft + bndright) / 2;
|
||||||
|
@ -104,6 +105,10 @@ void CameraLogic::Update(const ControllerEmu::Cursor::StateData& cursor,
|
||||||
MatrixRotationByZ(rot, ir_sin, ir_cos);
|
MatrixRotationByZ(rot, ir_sin, ir_cos);
|
||||||
MatrixMultiply(tot, scale, rot);
|
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++)
|
for (std::size_t i = 0; i < v.size(); i++)
|
||||||
{
|
{
|
||||||
MatrixTransformVertex(tot, v[i]);
|
MatrixTransformVertex(tot, v[i]);
|
||||||
|
@ -113,6 +118,12 @@ void CameraLogic::Update(const ControllerEmu::Cursor::StateData& cursor,
|
||||||
|
|
||||||
x[i] = static_cast<u16>(lround((v[i].x + 1) / 2 * (camWidth - 1)));
|
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)));
|
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
|
// IR data is read from offset 0x37 on real hardware
|
||||||
|
@ -127,70 +138,70 @@ void CameraLogic::Update(const ControllerEmu::Cursor::StateData& cursor,
|
||||||
switch (reg_data.mode)
|
switch (reg_data.mode)
|
||||||
{
|
{
|
||||||
case IR_MODE_BASIC:
|
case IR_MODE_BASIC:
|
||||||
{
|
|
||||||
auto* const irdata = reinterpret_cast<IRBasic*>(data);
|
|
||||||
for (unsigned int i = 0; i < 2; ++i)
|
for (unsigned int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
if (x[i * 2] < 1024 && y[i * 2] < 768)
|
IRBasic irdata = {};
|
||||||
{
|
|
||||||
irdata[i].x1 = static_cast<u8>(x[i * 2]);
|
|
||||||
irdata[i].x1hi = x[i * 2] >> 8;
|
|
||||||
|
|
||||||
irdata[i].y1 = static_cast<u8>(y[i * 2]);
|
irdata.x1 = static_cast<u8>(x[i * 2]);
|
||||||
irdata[i].y1hi = y[i * 2] >> 8;
|
irdata.x1hi = x[i * 2] >> 8;
|
||||||
}
|
irdata.y1 = static_cast<u8>(y[i * 2]);
|
||||||
if (x[i * 2 + 1] < 1024 && y[i * 2 + 1] < 768)
|
irdata.y1hi = y[i * 2] >> 8;
|
||||||
{
|
|
||||||
irdata[i].x2 = static_cast<u8>(x[i * 2 + 1]);
|
|
||||||
irdata[i].x2hi = x[i * 2 + 1] >> 8;
|
|
||||||
|
|
||||||
irdata[i].y2 = static_cast<u8>(y[i * 2 + 1]);
|
irdata.x2 = static_cast<u8>(x[i * 2 + 1]);
|
||||||
irdata[i].y2hi = y[i * 2 + 1] >> 8;
|
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;
|
break;
|
||||||
}
|
|
||||||
case IR_MODE_EXTENDED:
|
case IR_MODE_EXTENDED:
|
||||||
{
|
|
||||||
auto* const irdata = reinterpret_cast<IRExtended*>(data);
|
|
||||||
for (unsigned int i = 0; i < 4; ++i)
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
if (x[i] < 1024 && y[i] < 768)
|
|
||||||
{
|
{
|
||||||
irdata[i].x = static_cast<u8>(x[i]);
|
if (x[i] < camWidth)
|
||||||
irdata[i].xhi = x[i] >> 8;
|
{
|
||||||
|
IRExtended irdata = {};
|
||||||
|
|
||||||
irdata[i].y = static_cast<u8>(y[i]);
|
irdata.x = static_cast<u8>(x[i]);
|
||||||
irdata[i].yhi = y[i] >> 8;
|
irdata.xhi = x[i] >> 8;
|
||||||
|
|
||||||
irdata[i].size = 10;
|
irdata.y = static_cast<u8>(y[i]);
|
||||||
|
irdata.yhi = y[i] >> 8;
|
||||||
|
|
||||||
|
irdata.size = 10;
|
||||||
|
|
||||||
|
Common::BitCastPtr<IRExtended>(data + i * sizeof(IRExtended)) = irdata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case IR_MODE_FULL:
|
case IR_MODE_FULL:
|
||||||
{
|
|
||||||
auto* const irdata = reinterpret_cast<IRFull*>(data);
|
|
||||||
for (unsigned int i = 0; i < 4; ++i)
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
if (x[i] < 1024 && y[i] < 768)
|
|
||||||
{
|
{
|
||||||
irdata[i].x = static_cast<u8>(x[i]);
|
if (x[i] < camWidth)
|
||||||
irdata[i].xhi = x[i] >> 8;
|
{
|
||||||
|
IRFull irdata = {};
|
||||||
|
|
||||||
irdata[i].y = static_cast<u8>(y[i]);
|
irdata.x = static_cast<u8>(x[i]);
|
||||||
irdata[i].yhi = y[i] >> 8;
|
irdata.xhi = x[i] >> 8;
|
||||||
|
|
||||||
irdata[i].size = 10;
|
irdata.y = static_cast<u8>(y[i]);
|
||||||
|
irdata.yhi = y[i] >> 8;
|
||||||
|
|
||||||
|
irdata.size = 10;
|
||||||
|
|
||||||
// TODO: implement these sensibly:
|
// TODO: implement these sensibly:
|
||||||
// TODO: do high bits of x/y min/max need to be set to zero?
|
// TODO: do high bits of x/y min/max need to be set to zero?
|
||||||
irdata[i].xmin = 0;
|
irdata.xmin = 0;
|
||||||
irdata[i].ymin = 0;
|
irdata.ymin = 0;
|
||||||
irdata[i].xmax = 0;
|
irdata.xmax = 0;
|
||||||
irdata[i].ymax = 0;
|
irdata.ymax = 0;
|
||||||
irdata[i].zero = 0;
|
irdata.zero = 0;
|
||||||
irdata[i].intensity = 0;
|
irdata.intensity = 0;
|
||||||
|
|
||||||
|
Common::BitCastPtr<IRFull>(data + i * sizeof(IRFull)) = irdata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
// This seems to be fairly common, 0xff data is sent in this case:
|
// 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.");
|
// WARN_LOG(WIIMOTE, "Game is requesting IR data before setting IR mode.");
|
||||||
|
|
|
@ -64,6 +64,13 @@ public:
|
||||||
IR_MODE_FULL = 5,
|
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:
|
private:
|
||||||
// TODO: some of this memory is write-only and should return error 7.
|
// TODO: some of this memory is write-only and should return error 7.
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
@ -85,20 +92,13 @@ private:
|
||||||
static_assert(0x100 == sizeof(Register));
|
static_assert(0x100 == sizeof(Register));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr u8 I2C_ADDR = 0x58;
|
|
||||||
|
|
||||||
// The real wiimote reads camera data from the i2c bus at offset 0x37:
|
// The real wiimote reads camera data from the i2c bus at offset 0x37:
|
||||||
static const u8 REPORT_DATA_OFFSET = offsetof(Register, camera_data);
|
static const u8 REPORT_DATA_OFFSET = offsetof(Register, camera_data);
|
||||||
|
|
||||||
void Reset();
|
|
||||||
void DoState(PointerWrap& p);
|
|
||||||
void Update(const ControllerEmu::Cursor::StateData& cursor, const NormalizedAccelData& accel,
|
|
||||||
bool sensor_bar_on_top);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Register reg_data;
|
|
||||||
|
|
||||||
int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) override;
|
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;
|
int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) override;
|
||||||
|
|
||||||
|
Register reg_data;
|
||||||
};
|
};
|
||||||
} // namespace WiimoteEmu
|
} // namespace WiimoteEmu
|
||||||
|
|
|
@ -37,9 +37,11 @@ void EmulateShake(NormalizedAccelData* const accel, ControllerEmu::Buttons* cons
|
||||||
shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX;
|
shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
shake_step[i] = 0;
|
shake_step[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmulateDynamicShake(NormalizedAccelData* const accel, DynamicData& dynamic_data,
|
void EmulateDynamicShake(NormalizedAccelData* const accel, DynamicData& dynamic_data,
|
||||||
ControllerEmu::Buttons* const buttons_group,
|
ControllerEmu::Buttons* const buttons_group,
|
||||||
|
|
|
@ -15,11 +15,11 @@ namespace WiimoteEmu
|
||||||
{
|
{
|
||||||
struct NormalizedAccelData
|
struct NormalizedAccelData
|
||||||
{
|
{
|
||||||
|
// Unit is 1G
|
||||||
double x, y, z;
|
double x, y, z;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used for a dynamic swing or
|
// Used for a dynamic swing or shake
|
||||||
// shake
|
|
||||||
struct DynamicData
|
struct DynamicData
|
||||||
{
|
{
|
||||||
std::array<int, 3> timing; // Hold length in frames for each axis
|
std::array<int, 3> timing; // Hold length in frames for each axis
|
||||||
|
@ -27,10 +27,8 @@ struct DynamicData
|
||||||
std::array<int, 3> executing_frames_left; // Number of frames to execute the intensity operation
|
std::array<int, 3> executing_frames_left; // Number of frames to execute the intensity operation
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used for a dynamic swing or
|
// Used for a dynamic swing or shake.
|
||||||
// shake. This is used to pass
|
// This is used to pass in data that defines the dynamic action
|
||||||
// in data that defines the dynamic
|
|
||||||
// action
|
|
||||||
struct DynamicConfiguration
|
struct DynamicConfiguration
|
||||||
{
|
{
|
||||||
double low_intensity;
|
double low_intensity;
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
|
@ -43,7 +45,7 @@ void Wiimote::HandleReportMode(const OutputReportMode& dr)
|
||||||
m_reporting_continuous = dr.continuous;
|
m_reporting_continuous = dr.continuous;
|
||||||
m_reporting_mode = dr.mode;
|
m_reporting_mode = dr.mode;
|
||||||
|
|
||||||
SendAck(OutputReportID::REPORT_MODE, ErrorCode::SUCCESS);
|
SendAck(OutputReportID::ReportMode, ErrorCode::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that we have enough bytes for the report before we run the handler.
|
// Tests that we have enough bytes for the report before we run the handler.
|
||||||
|
@ -53,9 +55,10 @@ void Wiimote::InvokeHandler(H&& handler, const WiimoteCommon::OutputReportGeneri
|
||||||
if (size < sizeof(T))
|
if (size < sizeof(T))
|
||||||
{
|
{
|
||||||
ERROR_LOG(WIIMOTE, "InvokeHandler: report: 0x%02x invalid size: %d", int(rpt.rpt_id), size);
|
ERROR_LOG(WIIMOTE, "InvokeHandler: report: 0x%02x invalid size: %d", int(rpt.rpt_id), size);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(this->*handler)(*reinterpret_cast<const T*>(rpt.data));
|
(this->*handler)(Common::BitCastPtr<T>(rpt.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we process the Output Reports that the Wii sends. Our response will be
|
// Here we process the Output Reports that the Wii sends. Our response will be
|
||||||
|
@ -77,7 +80,7 @@ void Wiimote::HIDOutputReport(const void* data, u32 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& rpt = *static_cast<const OutputReportGeneric*>(data);
|
auto& rpt = *static_cast<const OutputReportGeneric*>(data);
|
||||||
const int rpt_size = size - rpt.HEADER_SIZE;
|
const int rpt_size = size - OutputReportGeneric::HEADER_SIZE;
|
||||||
|
|
||||||
DEBUG_LOG(WIIMOTE, "HIDOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index,
|
DEBUG_LOG(WIIMOTE, "HIDOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index,
|
||||||
m_reporting_channel, int(rpt.rpt_id));
|
m_reporting_channel, int(rpt.rpt_id));
|
||||||
|
@ -88,37 +91,37 @@ void Wiimote::HIDOutputReport(const void* data, u32 size)
|
||||||
|
|
||||||
switch (rpt.rpt_id)
|
switch (rpt.rpt_id)
|
||||||
{
|
{
|
||||||
case OutputReportID::RUMBLE:
|
case OutputReportID::Rumble:
|
||||||
// This is handled above.
|
// This is handled above.
|
||||||
break;
|
break;
|
||||||
case OutputReportID::LEDS:
|
case OutputReportID::LED:
|
||||||
InvokeHandler<OutputReportLeds>(&Wiimote::HandleReportLeds, rpt, rpt_size);
|
InvokeHandler<OutputReportLeds>(&Wiimote::HandleReportLeds, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::REPORT_MODE:
|
case OutputReportID::ReportMode:
|
||||||
InvokeHandler<OutputReportMode>(&Wiimote::HandleReportMode, rpt, rpt_size);
|
InvokeHandler<OutputReportMode>(&Wiimote::HandleReportMode, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::IR_PIXEL_CLOCK:
|
case OutputReportID::IRPixelClock:
|
||||||
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleIRPixelClock, rpt, rpt_size);
|
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleIRPixelClock, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::SPEAKER_ENABLE:
|
case OutputReportID::SpeakerEnable:
|
||||||
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleSpeakerEnable, rpt, rpt_size);
|
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleSpeakerEnable, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::REQUEST_STATUS:
|
case OutputReportID::RequestStatus:
|
||||||
InvokeHandler<OutputReportRequestStatus>(&Wiimote::HandleRequestStatus, rpt, rpt_size);
|
InvokeHandler<OutputReportRequestStatus>(&Wiimote::HandleRequestStatus, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::WRITE_DATA:
|
case OutputReportID::WriteData:
|
||||||
InvokeHandler<OutputReportWriteData>(&Wiimote::HandleWriteData, rpt, rpt_size);
|
InvokeHandler<OutputReportWriteData>(&Wiimote::HandleWriteData, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::READ_DATA:
|
case OutputReportID::ReadData:
|
||||||
InvokeHandler<OutputReportReadData>(&Wiimote::HandleReadData, rpt, rpt_size);
|
InvokeHandler<OutputReportReadData>(&Wiimote::HandleReadData, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::SPEAKER_DATA:
|
case OutputReportID::SpeakerData:
|
||||||
InvokeHandler<OutputReportSpeakerData>(&Wiimote::HandleSpeakerData, rpt, rpt_size);
|
InvokeHandler<OutputReportSpeakerData>(&Wiimote::HandleSpeakerData, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::SPEAKER_MUTE:
|
case OutputReportID::SpeakerMute:
|
||||||
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleSpeakerMute, rpt, rpt_size);
|
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleSpeakerMute, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
case OutputReportID::IR_LOGIC:
|
case OutputReportID::IRLogic:
|
||||||
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleIRLogic, rpt, rpt_size);
|
InvokeHandler<OutputReportEnableFeature>(&Wiimote::HandleIRLogic, rpt, rpt_size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -134,7 +137,7 @@ void Wiimote::CallbackInterruptChannel(const u8* data, u32 size)
|
||||||
|
|
||||||
void Wiimote::SendAck(OutputReportID rpt_id, ErrorCode error_code)
|
void Wiimote::SendAck(OutputReportID rpt_id, ErrorCode error_code)
|
||||||
{
|
{
|
||||||
TypedHIDInputData<InputReportAck> rpt(InputReportID::ACK);
|
TypedHIDInputData<InputReportAck> rpt(InputReportID::Ack);
|
||||||
auto& ack = rpt.data;
|
auto& ack = rpt.data;
|
||||||
|
|
||||||
ack.buttons = m_status.buttons;
|
ack.buttons = m_status.buttons;
|
||||||
|
@ -229,7 +232,7 @@ void Wiimote::HandleRequestStatus(const OutputReportRequestStatus&)
|
||||||
// Max battery level seems to be 0xc8 (decimal 200)
|
// Max battery level seems to be 0xc8 (decimal 200)
|
||||||
constexpr u8 MAX_BATTERY_LEVEL = 0xc8;
|
constexpr u8 MAX_BATTERY_LEVEL = 0xc8;
|
||||||
|
|
||||||
m_status.battery = (u8)(m_battery_setting->GetValue() * MAX_BATTERY_LEVEL);
|
m_status.battery = u8(std::lround(m_battery_setting->GetValue() * MAX_BATTERY_LEVEL));
|
||||||
|
|
||||||
if (Core::WantsDeterminism())
|
if (Core::WantsDeterminism())
|
||||||
{
|
{
|
||||||
|
@ -240,7 +243,7 @@ void Wiimote::HandleRequestStatus(const OutputReportRequestStatus&)
|
||||||
// Less than 0x20 triggers the low-battery flag:
|
// Less than 0x20 triggers the low-battery flag:
|
||||||
m_status.battery_low = m_status.battery < 0x20;
|
m_status.battery_low = m_status.battery < 0x20;
|
||||||
|
|
||||||
TypedHIDInputData<InputReportStatus> rpt(InputReportID::STATUS);
|
TypedHIDInputData<InputReportStatus> rpt(InputReportID::Status);
|
||||||
rpt.data = m_status;
|
rpt.data = m_status;
|
||||||
CallbackInterruptChannel(rpt.GetData(), rpt.GetSize());
|
CallbackInterruptChannel(rpt.GetData(), rpt.GetSize());
|
||||||
}
|
}
|
||||||
|
@ -261,7 +264,7 @@ void Wiimote::HandleWriteData(const OutputReportWriteData& wd)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode error_code = ErrorCode::SUCCESS;
|
ErrorCode error_code = ErrorCode::Success;
|
||||||
|
|
||||||
switch (static_cast<AddressSpace>(wd.space))
|
switch (static_cast<AddressSpace>(wd.space))
|
||||||
{
|
{
|
||||||
|
@ -270,7 +273,7 @@ void Wiimote::HandleWriteData(const OutputReportWriteData& wd)
|
||||||
if (address + wd.size > EEPROM_FREE_SIZE)
|
if (address + wd.size > EEPROM_FREE_SIZE)
|
||||||
{
|
{
|
||||||
WARN_LOG(WIIMOTE, "WriteData: address + size out of bounds!");
|
WARN_LOG(WIIMOTE, "WriteData: address + size out of bounds!");
|
||||||
error_code = ErrorCode::INVALID_ADDRESS;
|
error_code = ErrorCode::InvalidAddress;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -279,7 +282,8 @@ void Wiimote::HandleWriteData(const OutputReportWriteData& wd)
|
||||||
// Write mii data to file
|
// Write mii data to file
|
||||||
if (address >= 0x0FCA && address < 0x12C0)
|
if (address >= 0x0FCA && address < 0x12C0)
|
||||||
{
|
{
|
||||||
// TODO: Only write parts of the Mii block
|
// TODO: Only write parts of the Mii block.
|
||||||
|
// TODO: Use fifferent files for different wiimote numbers.
|
||||||
std::ofstream file;
|
std::ofstream file;
|
||||||
File::OpenFStream(file, File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin",
|
File::OpenFStream(file, File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin",
|
||||||
std::ios::binary | std::ios::out);
|
std::ios::binary | std::ios::out);
|
||||||
|
@ -290,14 +294,14 @@ void Wiimote::HandleWriteData(const OutputReportWriteData& wd)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpace::I2C_BUS:
|
case AddressSpace::I2CBus:
|
||||||
case AddressSpace::I2C_BUS_ALT:
|
case AddressSpace::I2CBusAlt:
|
||||||
{
|
{
|
||||||
// Attempting to access the EEPROM directly over i2c results in error 8.
|
// Attempting to access the EEPROM directly over i2c results in error 8.
|
||||||
if (EEPROM_I2C_ADDR == m_read_request.slave_address)
|
if (EEPROM_I2C_ADDR == m_read_request.slave_address)
|
||||||
{
|
{
|
||||||
WARN_LOG(WIIMOTE, "Attempt to write EEPROM directly.");
|
WARN_LOG(WIIMOTE, "Attempt to write EEPROM directly.");
|
||||||
error_code = ErrorCode::INVALID_ADDRESS;
|
error_code = ErrorCode::InvalidAddress;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +310,7 @@ void Wiimote::HandleWriteData(const OutputReportWriteData& wd)
|
||||||
if (bytes_written != wd.size)
|
if (bytes_written != wd.size)
|
||||||
{
|
{
|
||||||
// A real wiimote gives error 7 for failed write to i2c bus (mainly a non-existant slave)
|
// A real wiimote gives error 7 for failed write to i2c bus (mainly a non-existant slave)
|
||||||
error_code = ErrorCode::NACK;
|
error_code = ErrorCode::Nack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -314,11 +318,11 @@ void Wiimote::HandleWriteData(const OutputReportWriteData& wd)
|
||||||
default:
|
default:
|
||||||
WARN_LOG(WIIMOTE, "WriteData: invalid address space: 0x%x", wd.space);
|
WARN_LOG(WIIMOTE, "WriteData: invalid address space: 0x%x", wd.space);
|
||||||
// A real wiimote gives error 6:
|
// A real wiimote gives error 6:
|
||||||
error_code = ErrorCode::INVALID_SPACE;
|
error_code = ErrorCode::InvalidSpace;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendAck(OutputReportID::WRITE_DATA, error_code);
|
SendAck(OutputReportID::WriteData, error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::HandleReportRumble(const WiimoteCommon::OutputReportRumble& rpt)
|
void Wiimote::HandleReportRumble(const WiimoteCommon::OutputReportRumble& rpt)
|
||||||
|
@ -333,7 +337,7 @@ void Wiimote::HandleReportLeds(const WiimoteCommon::OutputReportLeds& rpt)
|
||||||
m_status.leds = rpt.leds;
|
m_status.leds = rpt.leds;
|
||||||
|
|
||||||
if (rpt.ack)
|
if (rpt.ack)
|
||||||
SendAck(OutputReportID::LEDS, ErrorCode::SUCCESS);
|
SendAck(OutputReportID::LED, ErrorCode::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::HandleIRPixelClock(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
void Wiimote::HandleIRPixelClock(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
||||||
|
@ -343,7 +347,7 @@ void Wiimote::HandleIRPixelClock(const WiimoteCommon::OutputReportEnableFeature&
|
||||||
// FYI: Camera data is currently always updated. Ignoring pixel clock status.
|
// FYI: Camera data is currently always updated. Ignoring pixel clock status.
|
||||||
|
|
||||||
if (rpt.ack)
|
if (rpt.ack)
|
||||||
SendAck(OutputReportID::IR_PIXEL_CLOCK, ErrorCode::SUCCESS);
|
SendAck(OutputReportID::IRPixelClock, ErrorCode::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::HandleIRLogic(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
void Wiimote::HandleIRLogic(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
||||||
|
@ -353,7 +357,7 @@ void Wiimote::HandleIRLogic(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
||||||
m_status.ir = rpt.enable;
|
m_status.ir = rpt.enable;
|
||||||
|
|
||||||
if (rpt.ack)
|
if (rpt.ack)
|
||||||
SendAck(OutputReportID::IR_LOGIC, ErrorCode::SUCCESS);
|
SendAck(OutputReportID::IRLogic, ErrorCode::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::HandleSpeakerMute(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
void Wiimote::HandleSpeakerMute(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
||||||
|
@ -361,7 +365,7 @@ void Wiimote::HandleSpeakerMute(const WiimoteCommon::OutputReportEnableFeature&
|
||||||
m_speaker_mute = rpt.enable;
|
m_speaker_mute = rpt.enable;
|
||||||
|
|
||||||
if (rpt.ack)
|
if (rpt.ack)
|
||||||
SendAck(OutputReportID::SPEAKER_MUTE, ErrorCode::SUCCESS);
|
SendAck(OutputReportID::SpeakerMute, ErrorCode::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::HandleSpeakerEnable(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
void Wiimote::HandleSpeakerEnable(const WiimoteCommon::OutputReportEnableFeature& rpt)
|
||||||
|
@ -370,7 +374,7 @@ void Wiimote::HandleSpeakerEnable(const WiimoteCommon::OutputReportEnableFeature
|
||||||
m_status.speaker = rpt.enable;
|
m_status.speaker = rpt.enable;
|
||||||
|
|
||||||
if (rpt.ack)
|
if (rpt.ack)
|
||||||
SendAck(OutputReportID::SPEAKER_ENABLE, ErrorCode::SUCCESS);
|
SendAck(OutputReportID::SpeakerEnable, ErrorCode::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::HandleSpeakerData(const WiimoteCommon::OutputReportSpeakerData& rpt)
|
void Wiimote::HandleSpeakerData(const WiimoteCommon::OutputReportSpeakerData& rpt)
|
||||||
|
@ -437,7 +441,7 @@ bool Wiimote::ProcessReadDataRequest()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedHIDInputData<InputReportReadDataReply> rpt(InputReportID::READ_DATA_REPLY);
|
TypedHIDInputData<InputReportReadDataReply> rpt(InputReportID::ReadDataReply);
|
||||||
auto& reply = rpt.data;
|
auto& reply = rpt.data;
|
||||||
|
|
||||||
reply.buttons = m_status.buttons;
|
reply.buttons = m_status.buttons;
|
||||||
|
@ -446,7 +450,7 @@ bool Wiimote::ProcessReadDataRequest()
|
||||||
// Pre-fill with zeros in case of read-error or read < 16-bytes:
|
// Pre-fill with zeros in case of read-error or read < 16-bytes:
|
||||||
std::fill(std::begin(reply.data), std::end(reply.data), 0x00);
|
std::fill(std::begin(reply.data), std::end(reply.data), 0x00);
|
||||||
|
|
||||||
ErrorCode error_code = ErrorCode::SUCCESS;
|
ErrorCode error_code = ErrorCode::Success;
|
||||||
|
|
||||||
switch (m_read_request.space)
|
switch (m_read_request.space)
|
||||||
{
|
{
|
||||||
|
@ -460,7 +464,7 @@ bool Wiimote::ProcessReadDataRequest()
|
||||||
// The real Wiimote generate an error for the first
|
// The real Wiimote generate an error for the first
|
||||||
// request to 0x1770 if we dont't replicate that the game will never
|
// request to 0x1770 if we dont't replicate that the game will never
|
||||||
// read the calibration data at the beginning of Eeprom.
|
// read the calibration data at the beginning of Eeprom.
|
||||||
error_code = ErrorCode::INVALID_ADDRESS;
|
error_code = ErrorCode::InvalidAddress;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -483,14 +487,14 @@ bool Wiimote::ProcessReadDataRequest()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpace::I2C_BUS:
|
case AddressSpace::I2CBus:
|
||||||
case AddressSpace::I2C_BUS_ALT:
|
case AddressSpace::I2CBusAlt:
|
||||||
{
|
{
|
||||||
// Attempting to access the EEPROM directly over i2c results in error 8.
|
// Attempting to access the EEPROM directly over i2c results in error 8.
|
||||||
if (EEPROM_I2C_ADDR == m_read_request.slave_address)
|
if (EEPROM_I2C_ADDR == m_read_request.slave_address)
|
||||||
{
|
{
|
||||||
WARN_LOG(WIIMOTE, "Attempt to read EEPROM directly.");
|
WARN_LOG(WIIMOTE, "Attempt to read EEPROM directly.");
|
||||||
error_code = ErrorCode::INVALID_ADDRESS;
|
error_code = ErrorCode::InvalidAddress;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,7 +506,7 @@ bool Wiimote::ProcessReadDataRequest()
|
||||||
{
|
{
|
||||||
DEBUG_LOG(WIIMOTE, "Responding with read error 7 @ 0x%x @ 0x%x (%d)",
|
DEBUG_LOG(WIIMOTE, "Responding with read error 7 @ 0x%x @ 0x%x (%d)",
|
||||||
m_read_request.slave_address, m_read_request.address, m_read_request.size);
|
m_read_request.slave_address, m_read_request.address, m_read_request.size);
|
||||||
error_code = ErrorCode::NACK;
|
error_code = ErrorCode::Nack;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,11 +517,11 @@ bool Wiimote::ProcessReadDataRequest()
|
||||||
default:
|
default:
|
||||||
WARN_LOG(WIIMOTE, "ReadData: invalid address space: 0x%x", int(m_read_request.space));
|
WARN_LOG(WIIMOTE, "ReadData: invalid address space: 0x%x", int(m_read_request.space));
|
||||||
// A real wiimote gives error 6:
|
// A real wiimote gives error 6:
|
||||||
error_code = ErrorCode::INVALID_SPACE;
|
error_code = ErrorCode::InvalidSpace;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ErrorCode::SUCCESS != error_code)
|
if (ErrorCode::Success != error_code)
|
||||||
{
|
{
|
||||||
// Stop processing request on read error:
|
// Stop processing request on read error:
|
||||||
m_read_request.size = 0;
|
m_read_request.size = 0;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||||
|
@ -108,8 +109,7 @@ Classic::Classic() : EncryptedExtension(_trans("Classic"))
|
||||||
|
|
||||||
void Classic::Update()
|
void Classic::Update()
|
||||||
{
|
{
|
||||||
auto& classic_data = *reinterpret_cast<DataFormat*>(&m_reg.controller_data);
|
DataFormat classic_data = {};
|
||||||
classic_data = {};
|
|
||||||
|
|
||||||
// left stick
|
// left stick
|
||||||
{
|
{
|
||||||
|
@ -156,6 +156,8 @@ void Classic::Update()
|
||||||
|
|
||||||
// flip button bits
|
// flip button bits
|
||||||
classic_data.bt.hex ^= 0xFFFF;
|
classic_data.bt.hex ^= 0xFFFF;
|
||||||
|
|
||||||
|
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = classic_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Classic::IsButtonPressed() const
|
bool Classic::IsButtonPressed() const
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||||
|
@ -66,8 +67,7 @@ Drums::Drums() : EncryptedExtension(_trans("Drums"))
|
||||||
|
|
||||||
void Drums::Update()
|
void Drums::Update()
|
||||||
{
|
{
|
||||||
auto& drum_data = reinterpret_cast<DataFormat&>(m_reg.controller_data);
|
DataFormat drum_data = {};
|
||||||
drum_data = {};
|
|
||||||
|
|
||||||
// stick
|
// stick
|
||||||
{
|
{
|
||||||
|
@ -92,6 +92,8 @@ void Drums::Update()
|
||||||
|
|
||||||
// flip button bits
|
// flip button bits
|
||||||
drum_data.bt ^= 0xFFFF;
|
drum_data.bt ^= 0xFFFF;
|
||||||
|
|
||||||
|
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = drum_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drums::IsButtonPressed() const
|
bool Drums::IsButtonPressed() const
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace WiimoteEmu
|
||||||
class Extension : public ControllerEmu::EmulatedController, public I2CSlave
|
class Extension : public ControllerEmu::EmulatedController, public I2CSlave
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Extension(const char* name);
|
explicit Extension(const char* name);
|
||||||
|
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||||
|
@ -98,8 +99,7 @@ Guitar::Guitar() : EncryptedExtension(_trans("Guitar"))
|
||||||
|
|
||||||
void Guitar::Update()
|
void Guitar::Update()
|
||||||
{
|
{
|
||||||
auto& guitar_data = reinterpret_cast<DataFormat&>(m_reg.controller_data);
|
DataFormat guitar_data = {};
|
||||||
guitar_data = {};
|
|
||||||
|
|
||||||
// stick
|
// stick
|
||||||
{
|
{
|
||||||
|
@ -137,6 +137,8 @@ void Guitar::Update()
|
||||||
|
|
||||||
// flip button bits
|
// flip button bits
|
||||||
guitar_data.bt ^= 0xFFFF;
|
guitar_data.bt ^= 0xFFFF;
|
||||||
|
|
||||||
|
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = guitar_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Guitar::IsButtonPressed() const
|
bool Guitar::IsButtonPressed() const
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/MathUtil.h"
|
#include "Common/MathUtil.h"
|
||||||
|
@ -72,8 +73,7 @@ Nunchuk::Nunchuk() : EncryptedExtension(_trans("Nunchuk"))
|
||||||
|
|
||||||
void Nunchuk::Update()
|
void Nunchuk::Update()
|
||||||
{
|
{
|
||||||
auto& nc_data = *reinterpret_cast<DataFormat*>(&m_reg.controller_data);
|
DataFormat nc_data = {};
|
||||||
nc_data = {};
|
|
||||||
|
|
||||||
// stick
|
// stick
|
||||||
const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState();
|
const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState();
|
||||||
|
@ -129,6 +129,8 @@ void Nunchuk::Update()
|
||||||
nc_data.bt.acc_x_lsb = acc.x & 0x3;
|
nc_data.bt.acc_x_lsb = acc.x & 0x3;
|
||||||
nc_data.bt.acc_y_lsb = acc.y & 0x3;
|
nc_data.bt.acc_y_lsb = acc.y & 0x3;
|
||||||
nc_data.bt.acc_z_lsb = acc.z & 0x3;
|
nc_data.bt.acc_z_lsb = acc.z & 0x3;
|
||||||
|
|
||||||
|
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = nc_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Nunchuk::IsButtonPressed() const
|
bool Nunchuk::IsButtonPressed() const
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||||
|
@ -84,8 +85,7 @@ Turntable::Turntable() : EncryptedExtension(_trans("Turntable"))
|
||||||
|
|
||||||
void Turntable::Update()
|
void Turntable::Update()
|
||||||
{
|
{
|
||||||
auto& tt_data = reinterpret_cast<DataFormat&>(m_reg.controller_data);
|
DataFormat tt_data = {};
|
||||||
tt_data = {};
|
|
||||||
|
|
||||||
// stick
|
// stick
|
||||||
{
|
{
|
||||||
|
@ -137,6 +137,8 @@ void Turntable::Update()
|
||||||
// flip button bits :/
|
// flip button bits :/
|
||||||
tt_data.bt ^= (BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | BUTTON_R_GREEN | BUTTON_R_RED |
|
tt_data.bt ^= (BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | BUTTON_R_GREEN | BUTTON_R_RED |
|
||||||
BUTTON_R_BLUE | BUTTON_MINUS | BUTTON_PLUS | BUTTON_EUPHORIA);
|
BUTTON_R_BLUE | BUTTON_MINUS | BUTTON_PLUS | BUTTON_EUPHORIA);
|
||||||
|
|
||||||
|
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = tt_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Turntable::IsButtonPressed() const
|
bool Turntable::IsButtonPressed() const
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
static constexpr u8 REPORT_I2C_SLAVE = 0x52;
|
static constexpr u8 REPORT_I2C_SLAVE = 0x52;
|
||||||
static constexpr u8 REPORT_I2C_ADDR = 0x00;
|
static constexpr u8 REPORT_I2C_ADDR = 0x00;
|
||||||
|
|
||||||
ExtensionPort(I2CBus* i2c_bus);
|
explicit ExtensionPort(I2CBus* i2c_bus);
|
||||||
|
|
||||||
bool IsDeviceConnected() const;
|
bool IsDeviceConnected() const;
|
||||||
void AttachExtension(Extension* dev);
|
void AttachExtension(Extension* dev);
|
||||||
|
|
|
@ -25,7 +25,7 @@ void MotionPlus::Reset()
|
||||||
std::copy(std::begin(initial_id), std::end(initial_id), reg_data.ext_identifier);
|
std::copy(std::begin(initial_id), std::end(initial_id), reg_data.ext_identifier);
|
||||||
|
|
||||||
// TODO: determine meaning of calibration data:
|
// TODO: determine meaning of calibration data:
|
||||||
static const u8 cdata[32] = {
|
constexpr std::array<u8, 32> cdata = {
|
||||||
0x78, 0xd9, 0x78, 0x38, 0x77, 0x9d, 0x2f, 0x0c, 0xcf, 0xf0, 0x31,
|
0x78, 0xd9, 0x78, 0x38, 0x77, 0x9d, 0x2f, 0x0c, 0xcf, 0xf0, 0x31,
|
||||||
0xad, 0xc8, 0x0b, 0x5e, 0x39, 0x6f, 0x81, 0x7b, 0x89, 0x78, 0x51,
|
0xad, 0xc8, 0x0b, 0x5e, 0x39, 0x6f, 0x81, 0x7b, 0x89, 0x78, 0x51,
|
||||||
0x33, 0x60, 0xc9, 0xf5, 0x37, 0xc1, 0x2d, 0xe9, 0x15, 0x8d,
|
0x33, 0x60, 0xc9, 0xf5, 0x37, 0xc1, 0x2d, 0xe9, 0x15, 0x8d,
|
||||||
|
@ -34,7 +34,7 @@ void MotionPlus::Reset()
|
||||||
std::copy(std::begin(cdata), std::end(cdata), reg_data.calibration_data);
|
std::copy(std::begin(cdata), std::end(cdata), reg_data.calibration_data);
|
||||||
|
|
||||||
// TODO: determine the meaning behind this:
|
// TODO: determine the meaning behind this:
|
||||||
static const u8 cert[64] = {
|
constexpr std::array<u8, 64> cert = {
|
||||||
0x99, 0x1a, 0x07, 0x1b, 0x97, 0xf1, 0x11, 0x78, 0x0c, 0x42, 0x2b, 0x68, 0xdf,
|
0x99, 0x1a, 0x07, 0x1b, 0x97, 0xf1, 0x11, 0x78, 0x0c, 0x42, 0x2b, 0x68, 0xdf,
|
||||||
0x44, 0x38, 0x0d, 0x2b, 0x7e, 0xd6, 0x84, 0x84, 0x58, 0x65, 0xc9, 0xf2, 0x95,
|
0x44, 0x38, 0x0d, 0x2b, 0x7e, 0xd6, 0x84, 0x84, 0x58, 0x65, 0xc9, 0xf2, 0x95,
|
||||||
0xd9, 0xaf, 0xb6, 0xc4, 0x87, 0xd5, 0x18, 0xdb, 0x67, 0x3a, 0xc0, 0x71, 0xec,
|
0xd9, 0xaf, 0xb6, 0xc4, 0x87, 0xd5, 0x18, 0xdb, 0x67, 0x3a, 0xc0, 0x71, 0xec,
|
||||||
|
@ -52,7 +52,7 @@ void MotionPlus::DoState(PointerWrap& p)
|
||||||
|
|
||||||
bool MotionPlus::IsActive() const
|
bool MotionPlus::IsActive() const
|
||||||
{
|
{
|
||||||
return ACTIVE_DEVICE_ADDR << 1 == reg_data.ext_identifier[2];
|
return (ACTIVE_DEVICE_ADDR << 1) == reg_data.ext_identifier[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionPlus::PassthroughMode MotionPlus::GetPassthroughMode() const
|
MotionPlus::PassthroughMode MotionPlus::GetPassthroughMode() const
|
||||||
|
@ -69,7 +69,8 @@ int MotionPlus::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
|
||||||
{
|
{
|
||||||
if (IsActive())
|
if (IsActive())
|
||||||
{
|
{
|
||||||
// Motion plus does not respond to 0x53 when activated
|
// FYI: Motion plus does not respond to 0x53 when activated
|
||||||
|
|
||||||
if (ACTIVE_DEVICE_ADDR == slave_addr)
|
if (ACTIVE_DEVICE_ADDR == slave_addr)
|
||||||
return RawRead(®_data, addr, count, data_out);
|
return RawRead(®_data, addr, count, data_out);
|
||||||
else
|
else
|
||||||
|
@ -78,7 +79,9 @@ int MotionPlus::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (INACTIVE_DEVICE_ADDR == slave_addr)
|
if (INACTIVE_DEVICE_ADDR == slave_addr)
|
||||||
|
{
|
||||||
return RawRead(®_data, addr, count, data_out);
|
return RawRead(®_data, addr, count, data_out);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Passthrough to the connected extension (if any)
|
// Passthrough to the connected extension (if any)
|
||||||
|
@ -200,7 +203,7 @@ void MotionPlus::Update()
|
||||||
// It even works when removing the is_mp_data bit in the last byte
|
// It even works when removing the is_mp_data bit in the last byte
|
||||||
// My M+ non-inside gives: 61,46,45,aa,0,2 or b6,46,45,9a,0,2
|
// My M+ non-inside gives: 61,46,45,aa,0,2 or b6,46,45,9a,0,2
|
||||||
// static const u8 init_data[6] = {0x8e, 0xb0, 0x4f, 0x5a, 0xfc | 0x01, 0x02};
|
// static const u8 init_data[6] = {0x8e, 0xb0, 0x4f, 0x5a, 0xfc | 0x01, 0x02};
|
||||||
static const u8 init_data[6] = {0x81, 0x46, 0x46, 0xb6, 0x01, 0x02};
|
constexpr std::array<u8, 6> init_data = {0x81, 0x46, 0x46, 0xb6, 0x01, 0x02};
|
||||||
std::copy(std::begin(init_data), std::end(init_data), data);
|
std::copy(std::begin(init_data), std::end(init_data), data);
|
||||||
reg_data.cert_ready = 0x2;
|
reg_data.cert_ready = 0x2;
|
||||||
return;
|
return;
|
||||||
|
@ -208,7 +211,7 @@ void MotionPlus::Update()
|
||||||
|
|
||||||
if (0x2 == reg_data.cert_ready)
|
if (0x2 == reg_data.cert_ready)
|
||||||
{
|
{
|
||||||
static const u8 init_data[6] = {0x7f, 0xcf, 0xdf, 0x8b, 0x4f, 0x82};
|
constexpr std::array<u8, 6> init_data = {0x7f, 0xcf, 0xdf, 0x8b, 0x4f, 0x82};
|
||||||
std::copy(std::begin(init_data), std::end(init_data), data);
|
std::copy(std::begin(init_data), std::end(init_data), data);
|
||||||
reg_data.cert_ready = 0x8;
|
reg_data.cert_ready = 0x8;
|
||||||
return;
|
return;
|
||||||
|
@ -223,7 +226,7 @@ void MotionPlus::Update()
|
||||||
if (0x18 == reg_data.cert_ready)
|
if (0x18 == reg_data.cert_ready)
|
||||||
{
|
{
|
||||||
// TODO: determine the meaning of this
|
// TODO: determine the meaning of this
|
||||||
const u8 mp_cert2[64] = {
|
constexpr std::array<u8, 64> mp_cert2 = {
|
||||||
0xa5, 0x84, 0x1f, 0xd6, 0xbd, 0xdc, 0x7a, 0x4c, 0xf3, 0xc0, 0x24, 0xe0, 0x92,
|
0xa5, 0x84, 0x1f, 0xd6, 0xbd, 0xdc, 0x7a, 0x4c, 0xf3, 0xc0, 0x24, 0xe0, 0x92,
|
||||||
0xef, 0x19, 0x28, 0x65, 0xe0, 0x62, 0x7c, 0x9b, 0x41, 0x6f, 0x12, 0xc3, 0xac,
|
0xef, 0x19, 0x28, 0x65, 0xe0, 0x62, 0x7c, 0x9b, 0x41, 0x6f, 0x12, 0xc3, 0xac,
|
||||||
0x78, 0xe4, 0xfc, 0x6b, 0x7b, 0x0a, 0xb4, 0x50, 0xd6, 0xf2, 0x45, 0xf7, 0x93,
|
0x78, 0xe4, 0xfc, 0x6b, 0x7b, 0x0a, 0xb4, 0x50, 0xd6, 0xf2, 0x45, 0xf7, 0x93,
|
||||||
|
@ -267,7 +270,7 @@ void MotionPlus::Update()
|
||||||
constexpr u8 EXT_ADDR = ExtensionPort::REPORT_I2C_ADDR;
|
constexpr u8 EXT_ADDR = ExtensionPort::REPORT_I2C_ADDR;
|
||||||
|
|
||||||
// Try to alternate between M+ and EXT data:
|
// Try to alternate between M+ and EXT data:
|
||||||
auto& mplus_data = *reinterpret_cast<DataFormat*>(data);
|
DataFormat mplus_data = Common::BitCastPtr<DataFormat>(data);
|
||||||
mplus_data.is_mp_data ^= true;
|
mplus_data.is_mp_data ^= true;
|
||||||
|
|
||||||
// hax!!!
|
// hax!!!
|
||||||
|
@ -282,13 +285,13 @@ void MotionPlus::Update()
|
||||||
{
|
{
|
||||||
switch (GetPassthroughMode())
|
switch (GetPassthroughMode())
|
||||||
{
|
{
|
||||||
case PassthroughMode::DISABLED:
|
case PassthroughMode::Disabled:
|
||||||
{
|
{
|
||||||
// Passthrough disabled, always send M+ data:
|
// Passthrough disabled, always send M+ data:
|
||||||
mplus_data.is_mp_data = true;
|
mplus_data.is_mp_data = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PassthroughMode::NUNCHUK:
|
case PassthroughMode::Nunchuk:
|
||||||
{
|
{
|
||||||
if (EXT_AMT == i2c_bus.BusRead(EXT_SLAVE, EXT_ADDR, EXT_AMT, data))
|
if (EXT_AMT == i2c_bus.BusRead(EXT_SLAVE, EXT_ADDR, EXT_AMT, data))
|
||||||
{
|
{
|
||||||
|
@ -315,7 +318,7 @@ void MotionPlus::Update()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PassthroughMode::CLASSIC:
|
case PassthroughMode::Classic:
|
||||||
{
|
{
|
||||||
if (EXT_AMT == i2c_bus.BusRead(EXT_SLAVE, EXT_ADDR, EXT_AMT, data))
|
if (EXT_AMT == i2c_bus.BusRead(EXT_SLAVE, EXT_ADDR, EXT_AMT, data))
|
||||||
{
|
{
|
||||||
|
@ -371,6 +374,8 @@ void MotionPlus::Update()
|
||||||
|
|
||||||
mplus_data.extension_connected = m_extension_port.IsDeviceConnected();
|
mplus_data.extension_connected = m_extension_port.IsDeviceConnected();
|
||||||
mplus_data.zero = 0;
|
mplus_data.zero = 0;
|
||||||
|
|
||||||
|
Common::BitCastPtr<DataFormat>(data) = mplus_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace WiimoteEmu
|
} // namespace WiimoteEmu
|
||||||
|
|
|
@ -96,9 +96,9 @@ private:
|
||||||
|
|
||||||
enum class PassthroughMode : u8
|
enum class PassthroughMode : u8
|
||||||
{
|
{
|
||||||
DISABLED = 0x04,
|
Disabled = 0x04,
|
||||||
NUNCHUK = 0x05,
|
Nunchuk = 0x05,
|
||||||
CLASSIC = 0x07,
|
Classic = 0x07,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsActive() const;
|
bool IsActive() const;
|
||||||
|
|
|
@ -71,7 +71,7 @@ void Wiimote::Reset()
|
||||||
|
|
||||||
// Wiimote starts in non-continuous CORE mode:
|
// Wiimote starts in non-continuous CORE mode:
|
||||||
m_reporting_channel = 0;
|
m_reporting_channel = 0;
|
||||||
m_reporting_mode = InputReportID::REPORT_CORE;
|
m_reporting_mode = InputReportID::ReportCore;
|
||||||
m_reporting_continuous = false;
|
m_reporting_continuous = false;
|
||||||
|
|
||||||
m_speaker_mute = false;
|
m_speaker_mute = false;
|
||||||
|
@ -325,7 +325,7 @@ bool Wiimote::ProcessExtensionPortEvent()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// FYI: This happens even during a read request which continues after the status report is sent.
|
// FYI: This happens even during a read request which continues after the status report is sent.
|
||||||
m_reporting_mode = InputReportID::REPORT_DISABLED;
|
m_reporting_mode = InputReportID::ReportDisabled;
|
||||||
|
|
||||||
DEBUG_LOG(WIIMOTE, "Sending status report due to extension status change.");
|
DEBUG_LOG(WIIMOTE, "Sending status report due to extension status change.");
|
||||||
|
|
||||||
|
@ -382,14 +382,14 @@ void Wiimote::SendDataReport()
|
||||||
{
|
{
|
||||||
Movie::SetPolledDevice();
|
Movie::SetPolledDevice();
|
||||||
|
|
||||||
if (InputReportID::REPORT_DISABLED == m_reporting_mode)
|
if (InputReportID::ReportDisabled == m_reporting_mode)
|
||||||
{
|
{
|
||||||
// The wiimote is in this disabled after an extension change.
|
// The wiimote is in this disabled after an extension change.
|
||||||
// Input reports are not sent, even on button change.
|
// Input reports are not sent, even on button change.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InputReportID::REPORT_CORE == m_reporting_mode && !m_reporting_continuous)
|
if (InputReportID::ReportCore == m_reporting_mode && !m_reporting_continuous)
|
||||||
{
|
{
|
||||||
// TODO: we only need to send a report if the data changed when m_reporting_continuous is
|
// TODO: we only need to send a report if the data changed when m_reporting_continuous is
|
||||||
// disabled. It's probably only sensible to check this with REPORT_CORE
|
// disabled. It's probably only sensible to check this with REPORT_CORE
|
||||||
|
@ -497,10 +497,10 @@ void Wiimote::SendDataReport()
|
||||||
CallbackInterruptChannel(rpt_builder.GetDataPtr(), rpt_builder.GetDataSize());
|
CallbackInterruptChannel(rpt_builder.GetDataPtr(), rpt_builder.GetDataSize());
|
||||||
|
|
||||||
// The interleaved reporting modes toggle back and forth:
|
// The interleaved reporting modes toggle back and forth:
|
||||||
if (InputReportID::REPORT_INTERLEAVE1 == m_reporting_mode)
|
if (InputReportID::ReportInterleave1 == m_reporting_mode)
|
||||||
m_reporting_mode = InputReportID::REPORT_INTERLEAVE2;
|
m_reporting_mode = InputReportID::ReportInterleave2;
|
||||||
else if (InputReportID::REPORT_INTERLEAVE2 == m_reporting_mode)
|
else if (InputReportID::ReportInterleave2 == m_reporting_mode)
|
||||||
m_reporting_mode = InputReportID::REPORT_INTERLEAVE1;
|
m_reporting_mode = InputReportID::ReportInterleave1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::ControlChannel(const u16 channel_id, const void* data, u32 size)
|
void Wiimote::ControlChannel(const u16 channel_id, const void* data, u32 size)
|
||||||
|
@ -550,7 +550,7 @@ void Wiimote::ControlChannel(const u16 channel_id, const void* data, u32 size)
|
||||||
{
|
{
|
||||||
// AyuanX: My experiment shows Control Channel is never used
|
// AyuanX: My experiment shows Control Channel is never used
|
||||||
// shuffle2: but lwbt uses this, so we'll do what we must :)
|
// shuffle2: but lwbt uses this, so we'll do what we must :)
|
||||||
HIDOutputReport(hidp.data, size - hidp.HEADER_SIZE);
|
HIDOutputReport(hidp.data, size - HIDPacket::HEADER_SIZE);
|
||||||
|
|
||||||
// TODO: Should this be above the previous?
|
// TODO: Should this be above the previous?
|
||||||
u8 handshake = HID_HANDSHAKE_SUCCESS;
|
u8 handshake = HID_HANDSHAKE_SUCCESS;
|
||||||
|
@ -594,7 +594,7 @@ void Wiimote::InterruptChannel(const u16 channel_id, const void* data, u32 size)
|
||||||
switch (hidp.param)
|
switch (hidp.param)
|
||||||
{
|
{
|
||||||
case HID_PARAM_OUTPUT:
|
case HID_PARAM_OUTPUT:
|
||||||
HIDOutputReport(hidp.data, size - hidp.HEADER_SIZE);
|
HIDOutputReport(hidp.data, size - HIDPacket::HEADER_SIZE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -449,7 +449,7 @@ bool IsWiimote(const std::basic_string<TCHAR>& device_path, WinWriteMethod& meth
|
||||||
Common::ScopeGuard handle_guard{[&dev_handle] { CloseHandle(dev_handle); }};
|
Common::ScopeGuard handle_guard{[&dev_handle] { CloseHandle(dev_handle); }};
|
||||||
|
|
||||||
u8 buf[MAX_PAYLOAD];
|
u8 buf[MAX_PAYLOAD];
|
||||||
u8 const req_status_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::REQUEST_STATUS), 0};
|
u8 const req_status_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::RequestStatus), 0};
|
||||||
int invalid_report_count = 0;
|
int invalid_report_count = 0;
|
||||||
int rc = WriteToHandle(dev_handle, method, req_status_report, sizeof(req_status_report));
|
int rc = WriteToHandle(dev_handle, method, req_status_report, sizeof(req_status_report));
|
||||||
while (rc > 0)
|
while (rc > 0)
|
||||||
|
@ -460,7 +460,7 @@ bool IsWiimote(const std::basic_string<TCHAR>& device_path, WinWriteMethod& meth
|
||||||
|
|
||||||
switch (InputReportID(buf[1]))
|
switch (InputReportID(buf[1]))
|
||||||
{
|
{
|
||||||
case InputReportID::STATUS:
|
case InputReportID::Status:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
WARN_LOG(WIIMOTE, "IsWiimote(): Received unexpected report %02x", buf[1]);
|
WARN_LOG(WIIMOTE, "IsWiimote(): Received unexpected report %02x", buf[1]);
|
||||||
|
@ -703,11 +703,11 @@ size_t GetReportSize(u8 rid)
|
||||||
|
|
||||||
switch (report_id)
|
switch (report_id)
|
||||||
{
|
{
|
||||||
case InputReportID::STATUS:
|
case InputReportID::Status:
|
||||||
return sizeof(InputReportStatus);
|
return sizeof(InputReportStatus);
|
||||||
case InputReportID::READ_DATA_REPLY:
|
case InputReportID::ReadDataReply:
|
||||||
return sizeof(InputReportReadDataReply);
|
return sizeof(InputReportReadDataReply);
|
||||||
case InputReportID::ACK:
|
case InputReportID::Ack:
|
||||||
return sizeof(InputReportAck);
|
return sizeof(InputReportAck);
|
||||||
default:
|
default:
|
||||||
if (DataReportBuilder::IsValidMode(report_id))
|
if (DataReportBuilder::IsValidMode(report_id))
|
||||||
|
|
|
@ -27,7 +27,7 @@ static bool IsDeviceUsable(const std::string& device_path)
|
||||||
// Some third-party adapters (DolphinBar) always expose all four Wii Remotes as HIDs
|
// Some third-party adapters (DolphinBar) always expose all four Wii Remotes as HIDs
|
||||||
// even when they are not connected, which causes an endless error loop when we try to use them.
|
// even when they are not connected, which causes an endless error loop when we try to use them.
|
||||||
// Try to write a report to the device to see if this Wii Remote is really usable.
|
// Try to write a report to the device to see if this Wii Remote is really usable.
|
||||||
static const u8 report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::REQUEST_STATUS), 0};
|
static const u8 report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::RequestStatus), 0};
|
||||||
const int result = hid_write(handle, report, sizeof(report));
|
const int result = hid_write(handle, report, sizeof(report));
|
||||||
// The DolphinBar uses EPIPE to signal the absence of a Wii Remote connected to this HID.
|
// The DolphinBar uses EPIPE to signal the absence of a Wii Remote connected to this HID.
|
||||||
if (result == -1 && errno != EPIPE)
|
if (result == -1 && errno != EPIPE)
|
||||||
|
|
|
@ -71,7 +71,7 @@ void Wiimote::WriteReport(Report rpt)
|
||||||
bool const new_rumble_state = (rpt[2] & 0x1) != 0;
|
bool const new_rumble_state = (rpt[2] & 0x1) != 0;
|
||||||
|
|
||||||
// If this is a rumble report and the rumble state didn't change, ignore.
|
// If this is a rumble report and the rumble state didn't change, ignore.
|
||||||
if (rpt[1] == u8(OutputReportID::RUMBLE) && new_rumble_state == m_rumble_state)
|
if (rpt[1] == u8(OutputReportID::Rumble) && new_rumble_state == m_rumble_state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_rumble_state = new_rumble_state;
|
m_rumble_state = new_rumble_state;
|
||||||
|
@ -99,10 +99,10 @@ void Wiimote::DisableDataReporting()
|
||||||
|
|
||||||
// This accomplishes very little:
|
// This accomplishes very little:
|
||||||
OutputReportMode rpt = {};
|
OutputReportMode rpt = {};
|
||||||
rpt.mode = InputReportID::REPORT_CORE;
|
rpt.mode = InputReportID::ReportCore;
|
||||||
rpt.continuous = 0;
|
rpt.continuous = 0;
|
||||||
rpt.rumble = 0;
|
rpt.rumble = 0;
|
||||||
QueueReport(u8(OutputReportID::REPORT_MODE), &rpt, sizeof(rpt));
|
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::EnableDataReporting(u8 mode)
|
void Wiimote::EnableDataReporting(u8 mode)
|
||||||
|
@ -112,7 +112,7 @@ void Wiimote::EnableDataReporting(u8 mode)
|
||||||
OutputReportMode rpt = {};
|
OutputReportMode rpt = {};
|
||||||
rpt.mode = InputReportID(mode);
|
rpt.mode = InputReportID(mode);
|
||||||
rpt.continuous = 1;
|
rpt.continuous = 1;
|
||||||
QueueReport(u8(OutputReportID::REPORT_MODE), &rpt, sizeof(rpt));
|
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::SetChannel(u16 channel)
|
void Wiimote::SetChannel(u16 channel)
|
||||||
|
@ -177,7 +177,7 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
|
||||||
|
|
||||||
// Disallow games from turning off all of the LEDs.
|
// Disallow games from turning off all of the LEDs.
|
||||||
// It makes Wiimote connection status confusing.
|
// It makes Wiimote connection status confusing.
|
||||||
if (rpt[1] == u8(OutputReportID::LEDS))
|
if (rpt[1] == u8(OutputReportID::LED))
|
||||||
{
|
{
|
||||||
auto& leds_rpt = *reinterpret_cast<OutputReportLeds*>(&rpt[2]);
|
auto& leds_rpt = *reinterpret_cast<OutputReportLeds*>(&rpt[2]);
|
||||||
if (0 == leds_rpt.leds)
|
if (0 == leds_rpt.leds)
|
||||||
|
@ -186,12 +186,12 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
|
||||||
leds_rpt.leds = 0xf;
|
leds_rpt.leds = 0xf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rpt[1] == u8(OutputReportID::SPEAKER_DATA) &&
|
else if (rpt[1] == u8(OutputReportID::SpeakerData) &&
|
||||||
(!SConfig::GetInstance().m_WiimoteEnableSpeaker ||
|
(!SConfig::GetInstance().m_WiimoteEnableSpeaker ||
|
||||||
(!wm->m_status.speaker || wm->m_speaker_mute)))
|
(!wm->m_status.speaker || wm->m_speaker_mute)))
|
||||||
{
|
{
|
||||||
// Translate speaker data reports into rumble reports.
|
// Translate speaker data reports into rumble reports.
|
||||||
rpt[1] = u8(OutputReportID::RUMBLE);
|
rpt[1] = u8(OutputReportID::Rumble);
|
||||||
// Keep only the rumble bit.
|
// Keep only the rumble bit.
|
||||||
rpt[2] &= 0x1;
|
rpt[2] &= 0x1;
|
||||||
rpt.resize(3);
|
rpt.resize(3);
|
||||||
|
@ -255,23 +255,11 @@ bool Wiimote::IsBalanceBoard()
|
||||||
return false;
|
return false;
|
||||||
// Initialise the extension by writing 0x55 to 0xa400f0, then writing 0x00 to 0xa400fb.
|
// Initialise the extension by writing 0x55 to 0xa400f0, then writing 0x00 to 0xa400fb.
|
||||||
// TODO: Use the structs for building these reports..
|
// TODO: Use the structs for building these reports..
|
||||||
static const u8 init_extension_rpt1[MAX_PAYLOAD] = {WR_SET_REPORT | BT_OUTPUT,
|
static const u8 init_extension_rpt1[MAX_PAYLOAD] = {
|
||||||
u8(OutputReportID::WRITE_DATA),
|
WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::WriteData), 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55};
|
||||||
0x04,
|
static const u8 init_extension_rpt2[MAX_PAYLOAD] = {
|
||||||
0xa4,
|
WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::WriteData), 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00};
|
||||||
0x00,
|
static const u8 status_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::RequestStatus),
|
||||||
0xf0,
|
|
||||||
0x01,
|
|
||||||
0x55};
|
|
||||||
static const u8 init_extension_rpt2[MAX_PAYLOAD] = {WR_SET_REPORT | BT_OUTPUT,
|
|
||||||
u8(OutputReportID::WRITE_DATA),
|
|
||||||
0x04,
|
|
||||||
0xa4,
|
|
||||||
0x00,
|
|
||||||
0xfb,
|
|
||||||
0x01,
|
|
||||||
0x00};
|
|
||||||
static const u8 status_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::REQUEST_STATUS),
|
|
||||||
0};
|
0};
|
||||||
if (!IOWrite(init_extension_rpt1, sizeof(init_extension_rpt1)) ||
|
if (!IOWrite(init_extension_rpt1, sizeof(init_extension_rpt1)) ||
|
||||||
!IOWrite(init_extension_rpt2, sizeof(init_extension_rpt2)))
|
!IOWrite(init_extension_rpt2, sizeof(init_extension_rpt2)))
|
||||||
|
@ -290,7 +278,7 @@ bool Wiimote::IsBalanceBoard()
|
||||||
|
|
||||||
switch (InputReportID(buf[1]))
|
switch (InputReportID(buf[1]))
|
||||||
{
|
{
|
||||||
case InputReportID::STATUS:
|
case InputReportID::Status:
|
||||||
{
|
{
|
||||||
const auto* status = reinterpret_cast<InputReportStatus*>(&buf[2]);
|
const auto* status = reinterpret_cast<InputReportStatus*>(&buf[2]);
|
||||||
// A Balance Board has a Balance Board extension.
|
// A Balance Board has a Balance Board extension.
|
||||||
|
@ -298,7 +286,7 @@ bool Wiimote::IsBalanceBoard()
|
||||||
return false;
|
return false;
|
||||||
// Read two bytes from 0xa400fe to identify the extension.
|
// Read two bytes from 0xa400fe to identify the extension.
|
||||||
static const u8 identify_ext_rpt[] = {WR_SET_REPORT | BT_OUTPUT,
|
static const u8 identify_ext_rpt[] = {WR_SET_REPORT | BT_OUTPUT,
|
||||||
u8(OutputReportID::READ_DATA),
|
u8(OutputReportID::ReadData),
|
||||||
0x04,
|
0x04,
|
||||||
0xa4,
|
0xa4,
|
||||||
0x00,
|
0x00,
|
||||||
|
@ -308,7 +296,7 @@ bool Wiimote::IsBalanceBoard()
|
||||||
ret = IOWrite(identify_ext_rpt, sizeof(identify_ext_rpt));
|
ret = IOWrite(identify_ext_rpt, sizeof(identify_ext_rpt));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InputReportID::READ_DATA_REPLY:
|
case InputReportID::ReadDataReply:
|
||||||
{
|
{
|
||||||
const auto* reply = reinterpret_cast<InputReportReadDataReply*>(&buf[2]);
|
const auto* reply = reinterpret_cast<InputReportReadDataReply*>(&buf[2]);
|
||||||
if (Common::swap16(reply->address) != 0x00fe)
|
if (Common::swap16(reply->address) != 0x00fe)
|
||||||
|
@ -320,10 +308,10 @@ bool Wiimote::IsBalanceBoard()
|
||||||
// A Balance Board ext can be identified by checking for 0x0402.
|
// A Balance Board ext can be identified by checking for 0x0402.
|
||||||
return reply->data[0] == 0x04 && reply->data[1] == 0x02;
|
return reply->data[0] == 0x04 && reply->data[1] == 0x02;
|
||||||
}
|
}
|
||||||
case InputReportID::ACK:
|
case InputReportID::Ack:
|
||||||
{
|
{
|
||||||
const auto* ack = reinterpret_cast<InputReportAck*>(&buf[2]);
|
const auto* ack = reinterpret_cast<InputReportAck*>(&buf[2]);
|
||||||
if (ack->rpt_id == OutputReportID::READ_DATA && ack->error_code != ErrorCode::SUCCESS)
|
if (ack->rpt_id == OutputReportID::ReadData && ack->error_code != ErrorCode::Success)
|
||||||
{
|
{
|
||||||
WARN_LOG(WIIMOTE, "Failed to read from 0xa400fe, assuming Wiimote is not a Balance Board.");
|
WARN_LOG(WIIMOTE, "Failed to read from 0xa400fe, assuming Wiimote is not a Balance Board.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -338,7 +326,7 @@ bool Wiimote::IsBalanceBoard()
|
||||||
|
|
||||||
static bool IsDataReport(const Report& rpt)
|
static bool IsDataReport(const Report& rpt)
|
||||||
{
|
{
|
||||||
return rpt.size() >= 2 && rpt[1] >= u8(InputReportID::REPORT_CORE);
|
return rpt.size() >= 2 && rpt[1] >= u8(InputReportID::ReportCore);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the next report that should be sent
|
// Returns the next report that should be sent
|
||||||
|
@ -387,30 +375,17 @@ void Wiimote::Update()
|
||||||
|
|
||||||
bool Wiimote::CheckForButtonPress()
|
bool Wiimote::CheckForButtonPress()
|
||||||
{
|
{
|
||||||
const Report& rpt = ProcessReadQueue();
|
Report& rpt = ProcessReadQueue();
|
||||||
if (rpt.size() >= 4)
|
if (rpt.size() >= 4)
|
||||||
{
|
{
|
||||||
switch (InputReportID(rpt[1]))
|
const auto mode = InputReportID(rpt[1]);
|
||||||
|
if (DataReportBuilder::IsValidMode(mode))
|
||||||
{
|
{
|
||||||
case InputReportID::REPORT_CORE:
|
auto builder = MakeDataReportManipulator(mode, rpt.data() + 2);
|
||||||
case InputReportID::REPORT_CORE_ACCEL:
|
ButtonData buttons = {};
|
||||||
case InputReportID::REPORT_CORE_EXT8:
|
builder->GetCoreData(&buttons);
|
||||||
case InputReportID::REPORT_CORE_ACCEL_IR12:
|
|
||||||
case InputReportID::REPORT_CORE_EXT19:
|
return buttons.hex != 0;
|
||||||
case InputReportID::REPORT_CORE_ACCEL_EXT16:
|
|
||||||
case InputReportID::REPORT_CORE_IR10_EXT9:
|
|
||||||
case InputReportID::REPORT_CORE_ACCEL_IR10_EXT6:
|
|
||||||
case InputReportID::REPORT_INTERLEAVE1:
|
|
||||||
case InputReportID::REPORT_INTERLEAVE2:
|
|
||||||
// check any button without checking accelerometer data
|
|
||||||
// TODO: use the structs!
|
|
||||||
if ((rpt[2] & 0x1F) != 0 || (rpt[3] & 0x9F) != 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -426,19 +401,19 @@ bool Wiimote::PrepareOnThread()
|
||||||
{
|
{
|
||||||
// core buttons, no continuous reporting
|
// core buttons, no continuous reporting
|
||||||
// TODO: use the structs..
|
// TODO: use the structs..
|
||||||
u8 static const mode_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::REPORT_MODE), 0,
|
u8 static const mode_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::ReportMode), 0,
|
||||||
u8(InputReportID::REPORT_CORE)};
|
u8(InputReportID::ReportCore)};
|
||||||
|
|
||||||
// Set the active LEDs and turn on rumble.
|
// Set the active LEDs and turn on rumble.
|
||||||
u8 static led_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::LEDS), 0};
|
u8 static led_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::LED), 0};
|
||||||
led_report[2] = u8(u8(LED::LED_1) << (m_index % WIIMOTE_BALANCE_BOARD) | 0x1);
|
led_report[2] = u8(u8(LED::LED_1) << (m_index % WIIMOTE_BALANCE_BOARD) | 0x1);
|
||||||
|
|
||||||
// Turn off rumble
|
// Turn off rumble
|
||||||
u8 static const rumble_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::RUMBLE), 0};
|
u8 static const rumble_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::Rumble), 0};
|
||||||
|
|
||||||
// Request status report
|
// Request status report
|
||||||
u8 static const req_status_report[] = {WR_SET_REPORT | BT_OUTPUT,
|
u8 static const req_status_report[] = {WR_SET_REPORT | BT_OUTPUT,
|
||||||
u8(OutputReportID::REQUEST_STATUS), 0};
|
u8(OutputReportID::RequestStatus), 0};
|
||||||
// TODO: check for sane response?
|
// TODO: check for sane response?
|
||||||
|
|
||||||
return (IOWrite(mode_report, sizeof(mode_report)) && IOWrite(led_report, sizeof(led_report)) &&
|
return (IOWrite(mode_report, sizeof(mode_report)) && IOWrite(led_report, sizeof(led_report)) &&
|
||||||
|
@ -473,7 +448,7 @@ void Wiimote::EmuResume()
|
||||||
OutputReportMode rpt = {};
|
OutputReportMode rpt = {};
|
||||||
rpt.mode = wm->m_reporting_mode;
|
rpt.mode = wm->m_reporting_mode;
|
||||||
rpt.continuous = 1;
|
rpt.continuous = 1;
|
||||||
QueueReport(u8(OutputReportID::REPORT_MODE), &rpt, sizeof(rpt));
|
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
|
||||||
|
|
||||||
NOTICE_LOG(WIIMOTE, "Resuming Wiimote data reporting.");
|
NOTICE_LOG(WIIMOTE, "Resuming Wiimote data reporting.");
|
||||||
|
|
||||||
|
@ -485,9 +460,9 @@ void Wiimote::EmuPause()
|
||||||
m_last_input_report.clear();
|
m_last_input_report.clear();
|
||||||
|
|
||||||
OutputReportMode rpt = {};
|
OutputReportMode rpt = {};
|
||||||
rpt.mode = InputReportID::REPORT_CORE;
|
rpt.mode = InputReportID::ReportCore;
|
||||||
rpt.continuous = 0;
|
rpt.continuous = 0;
|
||||||
QueueReport(u8(OutputReportID::REPORT_MODE), &rpt, sizeof(rpt));
|
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
|
||||||
|
|
||||||
NOTICE_LOG(WIIMOTE, "Pausing Wiimote data reporting.");
|
NOTICE_LOG(WIIMOTE, "Pausing Wiimote data reporting.");
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace WiimoteReal
|
||||||
{
|
{
|
||||||
using WiimoteCommon::MAX_PAYLOAD;
|
using WiimoteCommon::MAX_PAYLOAD;
|
||||||
|
|
||||||
typedef std::vector<u8> Report;
|
using Report = std::vector<u8>;
|
||||||
|
|
||||||
constexpr u32 WIIMOTE_DEFAULT_TIMEOUT = 1000;
|
constexpr u32 WIIMOTE_DEFAULT_TIMEOUT = 1000;
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "Core/HW/WiimoteEmu/Encryption.h"
|
#include "Core/HW/WiimoteEmu/Encryption.h"
|
||||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||||
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
||||||
|
#include "Core/HW/WiimoteEmu/ExtensionPort.h"
|
||||||
|
|
||||||
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
||||||
#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
|
#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
|
||||||
|
@ -706,7 +707,7 @@ static void SetWiiInputDisplayString(int remoteID, const DataReportBuilder& rpt,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nunchuk
|
// Nunchuk
|
||||||
if (rpt.HasExt() && ext == 1)
|
if (rpt.HasExt() && ext == ExtensionNumber::NUNCHUK)
|
||||||
{
|
{
|
||||||
const u8* const extData = rpt.GetExtDataPtr();
|
const u8* const extData = rpt.GetExtDataPtr();
|
||||||
|
|
||||||
|
@ -728,7 +729,7 @@ static void SetWiiInputDisplayString(int remoteID, const DataReportBuilder& rpt,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Classic controller
|
// Classic controller
|
||||||
if (rpt.HasExt() && ext == 2)
|
if (rpt.HasExt() && ext == ExtensionNumber::CLASSIC)
|
||||||
{
|
{
|
||||||
const u8* const extData = rpt.GetExtDataPtr();
|
const u8* const extData = rpt.GetExtDataPtr();
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,22 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/HW/WiimoteCommon/DataReport.h"
|
|
||||||
#include "Core/HW/WiimoteEmu/Encryption.h"
|
|
||||||
|
|
||||||
struct BootParameters;
|
struct BootParameters;
|
||||||
|
|
||||||
struct GCPadStatus;
|
struct GCPadStatus;
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
|
||||||
|
namespace WiimoteCommon
|
||||||
|
{
|
||||||
|
class DataReportBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace WiimoteEmu
|
||||||
|
{
|
||||||
|
class EncryptionKey;
|
||||||
|
}
|
||||||
|
|
||||||
// Per-(video )Movie actions
|
// Per-(video )Movie actions
|
||||||
|
|
||||||
namespace Movie
|
namespace Movie
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
#include "Core/Movie.h"
|
#include "Core/Movie.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/WiiRoot.h"
|
#include "Core/WiiRoot.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/Extension.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
||||||
#include "InputCommon/GCAdapter.h"
|
#include "InputCommon/GCAdapter.h"
|
||||||
#include "InputCommon/InputConfig.h"
|
#include "InputCommon/InputConfig.h"
|
||||||
#include "UICommon/GameFile.h"
|
#include "UICommon/GameFile.h"
|
||||||
|
@ -2191,11 +2191,10 @@ void SetupWiimotes()
|
||||||
{
|
{
|
||||||
if (wiimote_map[i] > 0)
|
if (wiimote_map[i] > 0)
|
||||||
{
|
{
|
||||||
static_cast<ControllerEmu::Extension*>(
|
static_cast<ControllerEmu::Attachments*>(
|
||||||
static_cast<WiimoteEmu::Wiimote*>(
|
static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(int(i)))
|
||||||
Wiimote::GetConfig()->GetController(static_cast<int>(i)))
|
->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments))
|
||||||
->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Extension))
|
->SetSelectedAttachment(netplay_settings.m_WiimoteExtension[i]);
|
||||||
->switch_extension = netplay_settings.m_WiimoteExtension[i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
#include "Core/IOS/IOS.h"
|
#include "Core/IOS/IOS.h"
|
||||||
#include "Core/NetPlayClient.h" //for NetPlayUI
|
#include "Core/NetPlayClient.h" //for NetPlayUI
|
||||||
#include "DiscIO/Enums.h"
|
#include "DiscIO/Enums.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/Extension.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
||||||
#include "InputCommon/GCPadStatus.h"
|
#include "InputCommon/GCPadStatus.h"
|
||||||
#include "InputCommon/InputConfig.h"
|
#include "InputCommon/InputConfig.h"
|
||||||
#include "UICommon/GameFile.h"
|
#include "UICommon/GameFile.h"
|
||||||
|
@ -1217,11 +1217,11 @@ bool NetPlayServer::StartGame()
|
||||||
|
|
||||||
for (size_t i = 0; i < m_settings.m_WiimoteExtension.size(); i++)
|
for (size_t i = 0; i < m_settings.m_WiimoteExtension.size(); i++)
|
||||||
{
|
{
|
||||||
const int extension = static_cast<ControllerEmu::Extension*>(
|
const int extension =
|
||||||
static_cast<WiimoteEmu::Wiimote*>(
|
static_cast<ControllerEmu::Attachments*>(
|
||||||
Wiimote::GetConfig()->GetController(static_cast<int>(i)))
|
static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(int(i)))
|
||||||
->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Extension))
|
->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments))
|
||||||
->switch_extension;
|
->GetSelectedAttachment();
|
||||||
spac << extension;
|
spac << extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,6 @@ public:
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<EmulatedController>> m_attachments;
|
std::vector<std::unique_ptr<EmulatedController>> m_attachments;
|
||||||
|
|
||||||
std::atomic<u32> m_selected_attachment;
|
std::atomic<u32> m_selected_attachment = {};
|
||||||
};
|
};
|
||||||
} // namespace ControllerEmu
|
} // namespace ControllerEmu
|
||||||
|
|
Loading…
Reference in New Issue