mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-20 11:35:54 +00:00
Implement input for balance board
This commit is contained in:
parent
7c316be1b4
commit
c0d748fc73
8 changed files with 195 additions and 26 deletions
|
@ -160,6 +160,12 @@ ControllerEmu::ControlGroup* GetShinkansenGroup(int number, WiimoteEmu::Shinkans
|
|||
->GetShinkansenGroup(group);
|
||||
}
|
||||
|
||||
ControllerEmu::ControlGroup* GetBalanceBoardGroup(int number, WiimoteEmu::BalanceBoardGroup group)
|
||||
{
|
||||
return static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number))
|
||||
->GetBalanceBoardGroup(group);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
s_config.UnregisterHotplugCallback();
|
||||
|
|
|
@ -29,6 +29,7 @@ enum class UDrawTabletGroup;
|
|||
enum class DrawsomeTabletGroup;
|
||||
enum class TaTaConGroup;
|
||||
enum class ShinkansenGroup;
|
||||
enum class BalanceBoardGroup;
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
enum
|
||||
|
@ -94,6 +95,7 @@ ControllerEmu::ControlGroup* GetDrawsomeTabletGroup(int number,
|
|||
WiimoteEmu::DrawsomeTabletGroup group);
|
||||
ControllerEmu::ControlGroup* GetTaTaConGroup(int number, WiimoteEmu::TaTaConGroup group);
|
||||
ControllerEmu::ControlGroup* GetShinkansenGroup(int number, WiimoteEmu::ShinkansenGroup group);
|
||||
ControllerEmu::ControlGroup* GetBalanceBoardGroup(int number, WiimoteEmu::BalanceBoardGroup group);
|
||||
} // namespace Wiimote
|
||||
|
||||
namespace WiimoteReal
|
||||
|
|
|
@ -20,10 +20,8 @@
|
|||
|
||||
#include "InputCommon/ControllerEmu/Control/Input.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Triggers.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
|
@ -31,18 +29,36 @@ constexpr std::array<u8, 6> balance_board_id{{0x00, 0x00, 0xa4, 0x20, 0x04, 0x02
|
|||
|
||||
BalanceBoardExt::BalanceBoardExt() : Extension1stParty("BalanceBoard", _trans("Balance Board"))
|
||||
{
|
||||
// balance
|
||||
groups.emplace_back(
|
||||
m_balance = new ControllerEmu::AnalogStick(
|
||||
_trans("Balance"), std::make_unique<ControllerEmu::SquareStickGate>(1.0)));
|
||||
groups.emplace_back(m_weight = new ControllerEmu::Triggers(_trans("Weight")));
|
||||
m_weight->controls.emplace_back(
|
||||
new ControllerEmu::Input(ControllerEmu::Translatability::Translate, _trans("Weight")));
|
||||
}
|
||||
|
||||
void BalanceBoardExt::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
||||
{
|
||||
const ControllerEmu::AnalogStick::StateData balance_state = m_balance->GetState();
|
||||
const ControllerEmu::Triggers::StateData weight_state = m_weight->GetState();
|
||||
const auto weight = weight_state.data[0];
|
||||
|
||||
const double total_weight = DEFAULT_WEIGHT * weight; // kilograms
|
||||
|
||||
const auto top_right = total_weight * (1 + balance_state.x + balance_state.y) / 4;
|
||||
const auto bottom_right = total_weight * (1 + balance_state.x - balance_state.y) / 4;
|
||||
const auto top_left = total_weight * (1 - balance_state.x + balance_state.y) / 4;
|
||||
const auto bottom_left = total_weight * (1 - balance_state.x - balance_state.y) / 4;
|
||||
|
||||
DataFormat bb_data = {};
|
||||
|
||||
bb_data.top_right = Common::swap16(0x0743);
|
||||
bb_data.bottom_right = Common::swap16(0x11a2);
|
||||
bb_data.top_left = Common::swap16(0x06a8);
|
||||
bb_data.bottom_left = Common::swap16(0x4694);
|
||||
bb_data.temperature = 0x19;
|
||||
bb_data.battery = 0x83;
|
||||
bb_data.top_right = Common::swap16(ConvertToSensorWeight(top_right));
|
||||
bb_data.bottom_right = Common::swap16(ConvertToSensorWeight(bottom_right));
|
||||
bb_data.top_left = Common::swap16(ConvertToSensorWeight(top_left));
|
||||
bb_data.bottom_left = Common::swap16(ConvertToSensorWeight(bottom_left));
|
||||
bb_data.temperature = TEMPERATURE;
|
||||
bb_data.battery = 0x83; // Above the threshold for 4 bars
|
||||
|
||||
target_state->data = bb_data;
|
||||
}
|
||||
|
@ -62,39 +78,48 @@ void BalanceBoardExt::Reset()
|
|||
m_reg.calibration = {{// Unused battery calibration
|
||||
0x01, 0x69, 0x00, 0x00,
|
||||
// Top right 0kg
|
||||
0x07, 0xbc,
|
||||
u8(WEIGHT_0_KG >> 8), u8(WEIGHT_0_KG & 0xFF),
|
||||
// Bottom right 0kg
|
||||
0x11, 0x8b,
|
||||
u8(WEIGHT_0_KG >> 8), u8(WEIGHT_0_KG & 0xFF),
|
||||
// Top left 0kg
|
||||
0x06, 0xba,
|
||||
u8(WEIGHT_0_KG >> 8), u8(WEIGHT_0_KG & 0xFF),
|
||||
// Bottom left 0kg
|
||||
0x46, 0x52,
|
||||
u8(WEIGHT_0_KG >> 8), u8(WEIGHT_0_KG & 0xFF),
|
||||
// Top right 17kg
|
||||
0x0e, 0x6e,
|
||||
u8(WEIGHT_17_KG >> 8), u8(WEIGHT_17_KG & 0xFF),
|
||||
// Bottom right 17kg
|
||||
0x18, 0x79}};
|
||||
u8(WEIGHT_17_KG >> 8), u8(WEIGHT_17_KG & 0xFF)}};
|
||||
m_reg.calibration2 = {{// Top left 17kg
|
||||
0x0d, 0x5d,
|
||||
u8(WEIGHT_17_KG >> 8), u8(WEIGHT_17_KG & 0xFF),
|
||||
// Bottom left 17kg
|
||||
0x4d, 0x4c,
|
||||
u8(WEIGHT_17_KG >> 8), u8(WEIGHT_17_KG & 0xFF),
|
||||
// Top right 34kg
|
||||
0x15, 0x2e,
|
||||
u8(WEIGHT_34_KG >> 8), u8(WEIGHT_34_KG & 0xFF),
|
||||
// Bottom right 34kg
|
||||
0x1f, 0x71,
|
||||
u8(WEIGHT_34_KG >> 8), u8(WEIGHT_34_KG & 0xFF),
|
||||
// Top left 34kg
|
||||
0x14, 0x07,
|
||||
u8(WEIGHT_34_KG >> 8), u8(WEIGHT_34_KG & 0xFF),
|
||||
// Bottom left 34kg
|
||||
0x54, 0x51,
|
||||
// Checksum
|
||||
0xa9, 0x06, 0xb4, 0xf0}};
|
||||
m_reg.calibration3 = {{0x19, 0x01}};
|
||||
u8(WEIGHT_34_KG >> 8), u8(WEIGHT_34_KG & 0xFF),
|
||||
// Checksum - computed later
|
||||
0xff, 0xff, 0xff, 0xff}};
|
||||
m_reg.calibration3 = {{TEMPERATURE, 0x01}};
|
||||
|
||||
// UpdateCalibrationDataChecksum(m_reg.calibration, CALIBRATION_CHECKSUM_BYTES);
|
||||
ComputeCalibrationChecksum();
|
||||
}
|
||||
|
||||
ControllerEmu::ControlGroup* BalanceBoardExt::GetGroup(BalanceBoardGroup group)
|
||||
{
|
||||
return nullptr;
|
||||
switch (group)
|
||||
{
|
||||
case BalanceBoardGroup::Balance:
|
||||
return m_balance;
|
||||
case BalanceBoardGroup::Weight:
|
||||
return m_weight;
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BalanceBoardExt::DoState(PointerWrap& p)
|
||||
|
@ -104,6 +129,89 @@ void BalanceBoardExt::DoState(PointerWrap& p)
|
|||
|
||||
void BalanceBoardExt::LoadDefaults(const ControllerInterface& ciface)
|
||||
{
|
||||
// Balance
|
||||
m_balance->SetControlExpression(0, "I"); // up
|
||||
m_balance->SetControlExpression(1, "K"); // down
|
||||
m_balance->SetControlExpression(2, "J"); // left
|
||||
m_balance->SetControlExpression(3, "L"); // right
|
||||
|
||||
// Because our defaults use keyboard input, set calibration shape to a square.
|
||||
m_balance->SetCalibrationFromGate(ControllerEmu::SquareStickGate(.5));
|
||||
}
|
||||
|
||||
u16 BalanceBoardExt::ConvertToSensorWeight(double weight_in_kilos)
|
||||
{
|
||||
constexpr u16 LOW_WEIGHT_DELTA = WEIGHT_17_KG - WEIGHT_0_KG;
|
||||
constexpr u16 HIGH_WEIGHT_DELTA = WEIGHT_34_KG - WEIGHT_17_KG;
|
||||
|
||||
// Note: this is the weight on a single sensor, so these ranges make more sense
|
||||
// (if all sensors read 34 kilos, then the overall weight would be 136 kilos or 300 pounds...)
|
||||
if (weight_in_kilos < 17)
|
||||
{
|
||||
return WEIGHT_0_KG + (LOW_WEIGHT_DELTA * weight_in_kilos / 17);
|
||||
}
|
||||
else
|
||||
{
|
||||
return WEIGHT_17_KG + (HIGH_WEIGHT_DELTA * (weight_in_kilos - 17) / 17);
|
||||
}
|
||||
}
|
||||
|
||||
void BalanceBoardExt::ComputeCalibrationChecksum()
|
||||
{
|
||||
std::array<u8, 0x1c> data;
|
||||
|
||||
data[0x00] = m_reg.calibration[0x4];
|
||||
data[0x01] = m_reg.calibration[0x5];
|
||||
data[0x02] = m_reg.calibration[0x6];
|
||||
data[0x03] = m_reg.calibration[0x7];
|
||||
data[0x04] = m_reg.calibration[0x8];
|
||||
data[0x05] = m_reg.calibration[0x9];
|
||||
data[0x06] = m_reg.calibration[0xa];
|
||||
data[0x07] = m_reg.calibration[0xb];
|
||||
data[0x08] = m_reg.calibration[0xc];
|
||||
data[0x09] = m_reg.calibration[0xd];
|
||||
data[0x0a] = m_reg.calibration[0xe];
|
||||
data[0x0b] = m_reg.calibration[0xf];
|
||||
data[0x0c] = m_reg.calibration2[0x0];
|
||||
data[0x0d] = m_reg.calibration2[0x1];
|
||||
data[0x0e] = m_reg.calibration2[0x2];
|
||||
data[0x0f] = m_reg.calibration2[0x3];
|
||||
data[0x10] = m_reg.calibration2[0x4];
|
||||
data[0x11] = m_reg.calibration2[0x5];
|
||||
data[0x12] = m_reg.calibration2[0x6];
|
||||
data[0x13] = m_reg.calibration2[0x7];
|
||||
data[0x14] = m_reg.calibration2[0x8];
|
||||
data[0x15] = m_reg.calibration2[0x9];
|
||||
data[0x16] = m_reg.calibration2[0xa];
|
||||
data[0x17] = m_reg.calibration2[0xb];
|
||||
data[0x18] = m_reg.calibration[0];
|
||||
data[0x19] = m_reg.calibration[1];
|
||||
data[0x1a] = m_reg.calibration3[0];
|
||||
data[0x1b] = m_reg.calibration3[1];
|
||||
|
||||
constexpr u32 CRC_POLYNOMIAL = 0xEDB88320; // Reversed
|
||||
|
||||
u32 result = 0xffffffff;
|
||||
for (auto byte : data)
|
||||
{
|
||||
// This could be cached into a table (and usually is), but since this is called infrequently and
|
||||
// on a small number of bytes, don't bother.
|
||||
u32 remainder = (byte ^ (result & 0xff));
|
||||
for (auto bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if (remainder & 1)
|
||||
remainder = (remainder >> 1) ^ CRC_POLYNOMIAL;
|
||||
else
|
||||
remainder = remainder >> 1;
|
||||
}
|
||||
|
||||
result = (result >> 8) ^ remainder;
|
||||
}
|
||||
result ^= 0xffffffff;
|
||||
|
||||
m_reg.calibration2[0x0c] = u8(result >> 24);
|
||||
m_reg.calibration2[0x0d] = u8(result >> 16);
|
||||
m_reg.calibration2[0x0e] = u8(result >> 8);
|
||||
m_reg.calibration2[0x0f] = u8(result);
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
|
|
@ -11,13 +11,17 @@
|
|||
|
||||
namespace ControllerEmu
|
||||
{
|
||||
class AnalogStick;
|
||||
class ControlGroup;
|
||||
class Triggers;
|
||||
} // namespace ControllerEmu
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
enum class BalanceBoardGroup
|
||||
{
|
||||
Balance,
|
||||
Weight
|
||||
};
|
||||
|
||||
class BalanceBoardExt : public Extension1stParty
|
||||
|
@ -37,6 +41,8 @@ public:
|
|||
|
||||
BalanceBoardExt();
|
||||
|
||||
static constexpr float DEFAULT_WEIGHT = 63.5; // kilograms; no specific meaning to this value
|
||||
|
||||
void BuildDesiredExtensionState(DesiredExtensionState* target_state) override;
|
||||
void Update(const DesiredExtensionState& target_state) override;
|
||||
void Reset() override;
|
||||
|
@ -46,6 +52,21 @@ public:
|
|||
|
||||
void LoadDefaults(const ControllerInterface& ciface) override;
|
||||
|
||||
// Use the same calibration data for all sensors.
|
||||
// Wii Fit appears to convert to this internally (so it doesn't care about differences smaller
|
||||
// than a gram). Normal balance boards tend to be less precise, usually around 10 grams.
|
||||
static constexpr u16 WEIGHT_0_KG = 0;
|
||||
static constexpr u16 WEIGHT_17_KG = 17000;
|
||||
static constexpr u16 WEIGHT_34_KG = 34000;
|
||||
// Chosen arbitrarily from the value for pokechu22's board. As long as the calibration and
|
||||
// actual temperatures match, the value here doesn't matter.
|
||||
static constexpr u8 TEMPERATURE = 0x19;
|
||||
|
||||
private:
|
||||
u16 ConvertToSensorWeight(double weight_in_kilos);
|
||||
void ComputeCalibrationChecksum();
|
||||
|
||||
ControllerEmu::AnalogStick* m_balance;
|
||||
ControllerEmu::Triggers* m_weight;
|
||||
};
|
||||
} // namespace WiimoteEmu
|
||||
|
|
|
@ -432,6 +432,13 @@ ControllerEmu::ControlGroup* Wiimote::GetShinkansenGroup(ShinkansenGroup group)
|
|||
->GetGroup(group);
|
||||
}
|
||||
|
||||
ControllerEmu::ControlGroup* Wiimote::GetBalanceBoardGroup(BalanceBoardGroup group) const
|
||||
{
|
||||
return static_cast<BalanceBoardExt*>(
|
||||
m_attachments->GetAttachmentList()[ExtensionNumber::BALANCE_BOARD].get())
|
||||
->GetGroup(group);
|
||||
}
|
||||
|
||||
bool Wiimote::ProcessExtensionPortEvent()
|
||||
{
|
||||
// WiiBrew: Following a connection or disconnection event on the Extension Port,
|
||||
|
|
|
@ -72,6 +72,7 @@ enum class UDrawTabletGroup;
|
|||
enum class DrawsomeTabletGroup;
|
||||
enum class TaTaConGroup;
|
||||
enum class ShinkansenGroup;
|
||||
enum class BalanceBoardGroup;
|
||||
|
||||
template <typename T>
|
||||
void UpdateCalibrationDataChecksum(T& data, int cksum_bytes)
|
||||
|
@ -155,6 +156,7 @@ public:
|
|||
ControllerEmu::ControlGroup* GetDrawsomeTabletGroup(DrawsomeTabletGroup group) const;
|
||||
ControllerEmu::ControlGroup* GetTaTaConGroup(TaTaConGroup group) const;
|
||||
ControllerEmu::ControlGroup* GetShinkansenGroup(ShinkansenGroup group) const;
|
||||
ControllerEmu::ControlGroup* GetBalanceBoardGroup(BalanceBoardGroup group) const;
|
||||
|
||||
u8 GetWiimoteDeviceIndex() const override;
|
||||
void SetWiimoteDeviceIndex(u8 index) override;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <QLabel>
|
||||
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/BalanceBoard.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Drums.h"
|
||||
|
@ -34,6 +35,7 @@ WiimoteEmuExtension::WiimoteEmuExtension(MappingWindow* window) : MappingWidget(
|
|||
CreateDrawsomeTabletLayout();
|
||||
CreateTaTaConLayout();
|
||||
CreateShinkansenLayout();
|
||||
CreateBalanceBoardLayout();
|
||||
CreateMainLayout();
|
||||
|
||||
ChangeExtensionType(WiimoteEmu::ExtensionNumber::NONE);
|
||||
|
@ -241,6 +243,23 @@ void WiimoteEmuExtension::CreateShinkansenLayout()
|
|||
m_shinkansen_box->setLayout(hbox);
|
||||
}
|
||||
|
||||
void WiimoteEmuExtension::CreateBalanceBoardLayout()
|
||||
{
|
||||
auto* layout = new QGridLayout();
|
||||
m_balance_board_box = new QGroupBox(tr("Balance Board"), this);
|
||||
|
||||
layout->addWidget(
|
||||
CreateGroupBox(tr("Balance"), Wiimote::GetBalanceBoardGroup(
|
||||
GetPort(), WiimoteEmu::BalanceBoardGroup::Balance)),
|
||||
0, 0);
|
||||
layout->addWidget(
|
||||
CreateGroupBox(tr("Balance"), Wiimote::GetBalanceBoardGroup(
|
||||
GetPort(), WiimoteEmu::BalanceBoardGroup::Weight)),
|
||||
0, 1);
|
||||
|
||||
m_balance_board_box->setLayout(layout);
|
||||
}
|
||||
|
||||
void WiimoteEmuExtension::CreateMainLayout()
|
||||
{
|
||||
m_main_layout = new QHBoxLayout();
|
||||
|
@ -255,6 +274,7 @@ void WiimoteEmuExtension::CreateMainLayout()
|
|||
m_main_layout->addWidget(m_drawsome_tablet_box);
|
||||
m_main_layout->addWidget(m_tatacon_box);
|
||||
m_main_layout->addWidget(m_shinkansen_box);
|
||||
m_main_layout->addWidget(m_balance_board_box);
|
||||
|
||||
setLayout(m_main_layout);
|
||||
}
|
||||
|
@ -288,4 +308,5 @@ void WiimoteEmuExtension::ChangeExtensionType(u32 type)
|
|||
m_drawsome_tablet_box->setHidden(type != ExtensionNumber::DRAWSOME_TABLET);
|
||||
m_tatacon_box->setHidden(type != ExtensionNumber::TATACON);
|
||||
m_shinkansen_box->setHidden(type != ExtensionNumber::SHINKANSEN);
|
||||
m_balance_board_box->setHidden(type != ExtensionNumber::BALANCE_BOARD);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ private:
|
|||
void CreateDrawsomeTabletLayout();
|
||||
void CreateTaTaConLayout();
|
||||
void CreateShinkansenLayout();
|
||||
void CreateBalanceBoardLayout();
|
||||
void CreateMainLayout();
|
||||
|
||||
// Main
|
||||
|
@ -48,4 +49,5 @@ private:
|
|||
QGroupBox* m_drawsome_tablet_box;
|
||||
QGroupBox* m_tatacon_box;
|
||||
QGroupBox* m_shinkansen_box;
|
||||
QGroupBox* m_balance_board_box;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue