AnalogController: Simplify rumble config

And fix some variables not being saved to state, yay determinism issues.
This commit is contained in:
Stenzek 2024-11-27 23:53:42 +10:00
parent 2e70d58f46
commit 4feed694d6
No known key found for this signature in database
3 changed files with 135 additions and 195 deletions

View File

@ -84,28 +84,64 @@ bool AnalogController::DoState(StateWrapper& sw, bool apply_input_state)
return false; return false;
const bool old_analog_mode = m_analog_mode; const bool old_analog_mode = m_analog_mode;
sw.Do(&m_analog_mode);
sw.Do(&m_dualshock_enabled);
sw.DoEx(&m_legacy_rumble_unlocked, 44, false);
sw.Do(&m_configuration_mode);
sw.Do(&m_command_param);
sw.DoEx(&m_status_byte, 55, static_cast<u8>(0x5A));
u16 button_state = m_button_state;
sw.DoEx(&button_state, 44, static_cast<u16>(0xFFFF));
if (apply_input_state)
m_button_state = button_state;
sw.Do(&m_command);
sw.DoEx(&m_rumble_config, 45, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
sw.DoEx(&m_rumble_config_large_motor_index, 45, -1);
sw.DoEx(&m_rumble_config_small_motor_index, 45, -1);
sw.DoEx(&m_analog_toggle_queued, 45, false);
MotorState motor_state = m_motor_state; MotorState motor_state = m_motor_state;
sw.Do(&motor_state);
if (sw.GetVersion() < 76) [[unlikely]]
{
u8 unused_command_param = 0;
bool unused_legacy_rumble_unlocked = false;
sw.Do(&m_analog_mode);
sw.Do(&m_dualshock_enabled);
sw.DoEx(&unused_legacy_rumble_unlocked, 44, false);
sw.Do(&m_configuration_mode);
sw.Do(&unused_command_param);
sw.DoEx(&m_status_byte, 55, static_cast<u8>(0x5A));
u16 button_state = m_button_state;
sw.DoEx(&button_state, 44, static_cast<u16>(0xFFFF));
if (apply_input_state)
m_button_state = button_state;
sw.Do(&m_command);
int unused_rumble_config_large_motor_index = -1;
int unused_rumble_config_small_motor_index = -1;
sw.DoEx(&m_rumble_config, 45, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
sw.DoEx(&unused_rumble_config_large_motor_index, 45, -1);
sw.DoEx(&unused_rumble_config_small_motor_index, 45, -1);
sw.DoEx(&m_analog_toggle_queued, 45, false);
sw.Do(&motor_state);
}
else
{
sw.Do(&m_command);
sw.Do(&m_command_step);
sw.Do(&m_response_length);
sw.DoBytes(m_rx_buffer.data(), m_rx_buffer.size());
sw.DoBytes(m_tx_buffer.data(), m_tx_buffer.size());
sw.Do(&m_analog_mode);
sw.Do(&m_analog_locked);
sw.Do(&m_dualshock_enabled);
sw.Do(&m_configuration_mode);
sw.DoBytes(m_rumble_config.data(), m_rumble_config.size());
sw.Do(&m_status_byte);
// sw.Do(&m_digital_mode_extra_halfwords); // always zero
auto axis_state = m_axis_state;
u16 button_state = m_button_state;
sw.DoBytes(axis_state.data(), axis_state.size());
sw.Do(&button_state);
sw.Do(&motor_state);
if (apply_input_state)
{
m_axis_state = axis_state;
m_button_state = button_state;
}
}
if (sw.IsReading()) if (sw.IsReading())
{ {
@ -368,8 +404,11 @@ void AnalogController::UpdateHostVibration()
std::array<float, NUM_MOTORS> hvalues; std::array<float, NUM_MOTORS> hvalues;
for (u32 motor = 0; motor < NUM_MOTORS; motor++) for (u32 motor = 0; motor < NUM_MOTORS; motor++)
{ {
// Small motor is only 0/1.
const u8 state =
(motor == SmallMotor) ? (((m_motor_state[SmallMotor] & 0x01) != 0x00) ? 255 : 0) : m_motor_state[LargeMotor];
// Curve from https://github.com/KrossX/Pokopom/blob/master/Pokopom/Input_XInput.cpp#L210 // Curve from https://github.com/KrossX/Pokopom/blob/master/Pokopom/Input_XInput.cpp#L210
const u8 state = m_motor_state[motor];
const double x = static_cast<double>(std::clamp<s32>(static_cast<s32>(state) + m_vibration_bias[motor], 0, 255)); const double x = static_cast<double>(std::clamp<s32>(static_cast<s32>(state) + m_vibration_bias[motor], 0, 255));
const double strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) + const double strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) +
156.82454281087692 * x + 3.637978807091713e-11; 156.82454281087692 * x + 3.637978807091713e-11;
@ -377,7 +416,8 @@ void AnalogController::UpdateHostVibration()
hvalues[motor] = (state != 0) ? static_cast<float>(strength / 65535.0) : 0.0f; hvalues[motor] = (state != 0) ? static_cast<float>(strength / 65535.0) : 0.0f;
} }
InputManager::SetPadVibrationIntensity(m_index, hvalues[0], hvalues[1]); WARNING_LOG("Set small to {}, large to {}", hvalues[SmallMotor], hvalues[LargeMotor]);
InputManager::SetPadVibrationIntensity(m_index, hvalues[LargeMotor], hvalues[SmallMotor]);
} }
u8 AnalogController::GetExtraButtonMaskLSB() const u8 AnalogController::GetExtraButtonMaskLSB() const
@ -402,20 +442,8 @@ u8 AnalogController::GetExtraButtonMaskLSB() const
void AnalogController::ResetRumbleConfig() void AnalogController::ResetRumbleConfig()
{ {
m_rumble_config.fill(0xFF); m_rumble_config.fill(0xFF);
m_rumble_config_large_motor_index = -1;
m_rumble_config_small_motor_index = -1;
SetMotorState(LargeMotor, 0);
SetMotorState(SmallMotor, 0); SetMotorState(SmallMotor, 0);
} SetMotorState(LargeMotor, 0);
void AnalogController::SetMotorStateForConfigIndex(int index, u8 value)
{
if (m_rumble_config_small_motor_index == index)
SetMotorState(SmallMotor, ((value & 0x01) != 0) ? 255 : 0);
else if (m_rumble_config_large_motor_index == index)
SetMotorState(LargeMotor, value);
} }
u8 AnalogController::GetResponseNumHalfwords() const u8 AnalogController::GetResponseNumHalfwords() const
@ -442,6 +470,29 @@ u8 AnalogController::GetIDByte() const
return Truncate8((GetModeID() << 4) | GetResponseNumHalfwords()); return Truncate8((GetModeID() << 4) | GetResponseNumHalfwords());
} }
void AnalogController::Poll()
{
// m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
m_tx_buffer[0] = GetIDByte();
m_tx_buffer[1] = m_status_byte;
m_tx_buffer[2] = Truncate8(m_button_state) & GetExtraButtonMaskLSB();
m_tx_buffer[3] = Truncate8(m_button_state >> 8);
if (m_analog_mode || m_configuration_mode)
{
m_tx_buffer[4] = m_axis_state[static_cast<u8>(Axis::RightX)];
m_tx_buffer[5] = m_axis_state[static_cast<u8>(Axis::RightY)];
m_tx_buffer[6] = m_axis_state[static_cast<u8>(Axis::LeftX)];
m_tx_buffer[7] = m_axis_state[static_cast<u8>(Axis::LeftY)];
}
else
{
m_tx_buffer[4] = 0;
m_tx_buffer[5] = 0;
m_tx_buffer[6] = 0;
m_tx_buffer[7] = 0;
}
}
bool AnalogController::Transfer(const u8 data_in, u8* data_out) bool AnalogController::Transfer(const u8 data_in, u8* data_out)
{ {
bool ack; bool ack;
@ -472,14 +523,17 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
Assert(m_command_step == 0); Assert(m_command_step == 0);
m_response_length = (GetResponseNumHalfwords() + 1) * 2; m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::ReadPad; m_command = Command::ReadPad;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; Poll();
} }
else if (data_in == 0x43) else if (data_in == 0x43)
{ {
Assert(m_command_step == 0); Assert(m_command_step == 0);
m_response_length = (GetResponseNumHalfwords() + 1) * 2; m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::ConfigModeSetMode; m_command = Command::ConfigModeSetMode;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (!m_configuration_mode)
Poll();
else
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
} }
else if (m_configuration_mode && data_in == 0x44) else if (m_configuration_mode && data_in == 0x44)
{ {
@ -524,9 +578,6 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
m_response_length = (GetResponseNumHalfwords() + 1) * 2; m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::GetSetRumble; m_command = Command::GetSetRumble;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
m_rumble_config_large_motor_index = -1;
m_rumble_config_small_motor_index = -1;
} }
else else
{ {
@ -541,136 +592,25 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
case Command::ReadPad: case Command::ReadPad:
{ {
const int rumble_index = m_command_step - 2; if (m_dualshock_enabled)
switch (m_command_step)
{ {
case 2: if (m_command_step >= 2 && m_command_step < 7)
{ {
m_tx_buffer[m_command_step] = Truncate8(m_button_state) & GetExtraButtonMaskLSB(); const u8 motor_to_set = m_rumble_config[m_command_step - 2];
if (motor_to_set <= LargeMotor)
if (m_dualshock_enabled) SetMotorState(motor_to_set, data_in);
SetMotorStateForConfigIndex(rumble_index, data_in);
} }
break; }
else if (m_command_step == 3)
case 3: {
{ const bool legacy_rumble_on = (m_rx_buffer[2] & 0xC0) == 0x40 && (m_rx_buffer[3] & 0x01) != 0;
m_tx_buffer[m_command_step] = Truncate8(m_button_state >> 8); SetMotorState(SmallMotor, legacy_rumble_on ? 255 : 0);
if (m_dualshock_enabled)
{
SetMotorStateForConfigIndex(rumble_index, data_in);
}
else
{
bool legacy_rumble_on = (m_rx_buffer[2] & 0xC0) == 0x40 && (m_rx_buffer[3] & 0x01) != 0;
SetMotorState(SmallMotor, legacy_rumble_on ? 255 : 0);
}
}
break;
case 4:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightX)];
if (m_dualshock_enabled)
SetMotorStateForConfigIndex(rumble_index, data_in);
}
break;
case 5:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightY)];
if (m_dualshock_enabled)
SetMotorStateForConfigIndex(rumble_index, data_in);
}
break;
case 6:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftX)];
if (m_dualshock_enabled)
SetMotorStateForConfigIndex(rumble_index, data_in);
}
break;
case 7:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftY)];
if (m_dualshock_enabled)
SetMotorStateForConfigIndex(rumble_index, data_in);
}
break;
default:
{
}
break;
} }
} }
break; break;
case Command::ConfigModeSetMode: case Command::ConfigModeSetMode:
{ {
if (!m_configuration_mode)
{
switch (m_command_step)
{
case 2:
{
m_tx_buffer[m_command_step] = Truncate8(m_button_state) & GetExtraButtonMaskLSB();
}
break;
case 3:
{
m_tx_buffer[m_command_step] = Truncate8(m_button_state >> 8);
}
break;
case 4:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightX)];
}
break;
case 5:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightY)];
}
break;
case 6:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftX)];
}
break;
case 7:
{
if (m_configuration_mode || m_analog_mode)
m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftY)];
}
break;
default:
{
}
break;
}
}
if (m_command_step == (static_cast<s32>(m_response_length) - 1)) if (m_command_step == (static_cast<s32>(m_response_length) - 1))
{ {
m_configuration_mode = (m_rx_buffer[2] == 1); m_configuration_mode = (m_rx_buffer[2] == 1);
@ -759,25 +699,31 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
case Command::GetSetRumble: case Command::GetSetRumble:
{ {
int rumble_index = m_command_step - 2; if (m_command_step >= 2 && m_command_step < 7)
if (rumble_index >= 0)
{ {
m_tx_buffer[m_command_step] = m_rumble_config[rumble_index]; const u8 index = m_command_step - 2;
m_rumble_config[rumble_index] = data_in; m_tx_buffer[m_command_step] = m_rumble_config[index];
m_rumble_config[index] = data_in;
if (data_in == 0x00) if (data_in == LargeMotor)
m_rumble_config_small_motor_index = rumble_index; WARNING_LOG("Large mapped to byte index {}", index);
else if (data_in == 0x01) else if (data_in == SmallMotor)
m_rumble_config_large_motor_index = rumble_index; WARNING_LOG("Small mapped to byte index {}", index);
} }
else if (m_command_step == 7)
if (m_command_step == 7)
{ {
if (m_rumble_config_large_motor_index == -1) // reset motor value if we're no longer mapping it
SetMotorState(LargeMotor, 0); bool has_small = false;
bool has_large = false;
if (m_rumble_config_small_motor_index == -1) for (size_t i = 0; i < m_rumble_config.size(); i++)
{
has_small |= (m_rumble_config[i] == SmallMotor);
has_large |= (m_rumble_config[i] == LargeMotor);
}
if (!has_small)
SetMotorState(SmallMotor, 0); SetMotorState(SmallMotor, 0);
if (!has_large)
SetMotorState(LargeMotor, 0);
} }
} }
break; break;
@ -813,14 +759,14 @@ std::unique_ptr<AnalogController> AnalogController::Create(u32 index)
static const Controller::ControllerBindingInfo s_binding_info[] = { static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, icon_name, button, genb) \ #define BUTTON(name, display_name, icon_name, button, genb) \
{ \ {name, display_name, icon_name, static_cast<u32>(button), InputBindingInfo::Type::Button, genb}
name, display_name, icon_name, static_cast<u32>(button), InputBindingInfo::Type::Button, genb \
}
#define AXIS(name, display_name, icon_name, halfaxis, genb) \ #define AXIS(name, display_name, icon_name, halfaxis, genb) \
{ \ {name, \
name, display_name, icon_name, static_cast<u32>(AnalogController::Button::Count) + static_cast<u32>(halfaxis), \ display_name, \
InputBindingInfo::Type::HalfAxis, genb \ icon_name, \
} static_cast<u32>(AnalogController::Button::Count) + static_cast<u32>(halfaxis), \
InputBindingInfo::Type::HalfAxis, \
genb}
// clang-format off // clang-format off
BUTTON("Up", TRANSLATE_NOOP("AnalogController", "D-Pad Up"), ICON_PF_DPAD_UP, AnalogController::Button::Up, GenericInputBinding::DPadUp), BUTTON("Up", TRANSLATE_NOOP("AnalogController", "D-Pad Up"), ICON_PF_DPAD_UP, AnalogController::Button::Up, GenericInputBinding::DPadUp),

View File

@ -103,13 +103,13 @@ private:
static constexpr s16 DEFAULT_LARGE_MOTOR_VIBRATION_BIAS = 8; static constexpr s16 DEFAULT_LARGE_MOTOR_VIBRATION_BIAS = 8;
Command m_command = Command::Idle; Command m_command = Command::Idle;
int m_command_step = 0; u8 m_command_step = 0;
u8 m_response_length = 0;
// Transmit and receive buffers, not including the first Hi-Z/ack response byte // Transmit and receive buffers, not including the first Hi-Z/ack response byte
static constexpr u32 MAX_RESPONSE_LENGTH = 8; static constexpr u32 MAX_RESPONSE_LENGTH = 8;
std::array<u8, MAX_RESPONSE_LENGTH> m_rx_buffer; std::array<u8, MAX_RESPONSE_LENGTH> m_rx_buffer;
std::array<u8, MAX_RESPONSE_LENGTH> m_tx_buffer; std::array<u8, MAX_RESPONSE_LENGTH> m_tx_buffer;
u32 m_response_length = 0;
// Get number of response halfwords (excluding the initial controller info halfword) // Get number of response halfwords (excluding the initial controller info halfword)
u8 GetResponseNumHalfwords() const; u8 GetResponseNumHalfwords() const;
@ -123,7 +123,7 @@ private:
void UpdateHostVibration(); void UpdateHostVibration();
u8 GetExtraButtonMaskLSB() const; u8 GetExtraButtonMaskLSB() const;
void ResetRumbleConfig(); void ResetRumbleConfig();
void SetMotorStateForConfigIndex(int index, u8 value); void Poll();
float m_analog_deadzone = 0.0f; float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f; float m_analog_sensitivity = 1.33f;
@ -143,13 +143,11 @@ private:
enum : u8 enum : u8
{ {
LargeMotor = 0, SmallMotor = 0,
SmallMotor = 1 LargeMotor = 1,
}; };
std::array<u8, 6> m_rumble_config{}; std::array<u8, 6> m_rumble_config{};
int m_rumble_config_large_motor_index = -1;
int m_rumble_config_small_motor_index = -1;
bool m_analog_toggle_queued = false; bool m_analog_toggle_queued = false;
u8 m_status_byte = 0; u8 m_status_byte = 0;
@ -164,8 +162,4 @@ private:
// both directions of axis state, merged to m_axis_state // both directions of axis state, merged to m_axis_state
std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{}; std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{};
// Member variables that are no longer used, but kept and serialized for compatibility with older save states
u8 m_command_param = 0;
bool m_legacy_rumble_unlocked = false;
}; };

View File

@ -6,7 +6,7 @@
#include "common/types.h" #include "common/types.h"
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 75; static constexpr u32 SAVE_STATE_VERSION = 76;
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42; static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION); static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);