WiimoteEmu: Code cleanups.

This commit is contained in:
Jordan Woyak 2019-01-05 07:09:11 -06:00
parent 3945aa6242
commit 9c1a8891e5
29 changed files with 352 additions and 297 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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); }

View File

@ -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.");

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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(&reg_data, addr, count, data_out); return RawRead(&reg_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(&reg_data, addr, count, data_out); return RawRead(&reg_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

View File

@ -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;

View File

@ -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:

View File

@ -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))

View File

@ -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)

View File

@ -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.");

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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];
} }
} }
} }

View File

@ -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;
} }

View File

@ -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