Implement input for balance board

This commit is contained in:
Pokechu22 2019-07-17 21:18:21 -07:00
parent 7c316be1b4
commit c0d748fc73
8 changed files with 195 additions and 26 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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