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,12 +84,18 @@ bool AnalogController::DoState(StateWrapper& sw, bool apply_input_state)
return false;
const bool old_analog_mode = m_analog_mode;
MotorState motor_state = m_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(&m_legacy_rumble_unlocked, 44, false);
sw.DoEx(&unused_legacy_rumble_unlocked, 44, false);
sw.Do(&m_configuration_mode);
sw.Do(&m_command_param);
sw.Do(&unused_command_param);
sw.DoEx(&m_status_byte, 55, static_cast<u8>(0x5A));
u16 button_state = m_button_state;
@ -99,13 +105,43 @@ bool AnalogController::DoState(StateWrapper& sw, bool apply_input_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(&m_rumble_config_large_motor_index, 45, -1);
sw.DoEx(&m_rumble_config_small_motor_index, 45, -1);
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);
MotorState motor_state = m_motor_state;
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())
{
@ -368,8 +404,11 @@ void AnalogController::UpdateHostVibration()
std::array<float, NUM_MOTORS> hvalues;
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
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 strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) +
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;
}
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
@ -402,20 +442,8 @@ u8 AnalogController::GetExtraButtonMaskLSB() const
void AnalogController::ResetRumbleConfig()
{
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);
}
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);
SetMotorState(LargeMotor, 0);
}
u8 AnalogController::GetResponseNumHalfwords() const
@ -442,6 +470,29 @@ u8 AnalogController::GetIDByte() const
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 ack;
@ -472,13 +523,16 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
Assert(m_command_step == 0);
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::ReadPad;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Poll();
}
else if (data_in == 0x43)
{
Assert(m_command_step == 0);
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::ConfigModeSetMode;
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)
@ -524,9 +578,6 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::GetSetRumble;
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
{
@ -541,136 +592,25 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
case Command::ReadPad:
{
const int rumble_index = m_command_step - 2;
switch (m_command_step)
{
case 2:
{
m_tx_buffer[m_command_step] = Truncate8(m_button_state) & GetExtraButtonMaskLSB();
if (m_dualshock_enabled)
SetMotorStateForConfigIndex(rumble_index, data_in);
}
break;
case 3:
{
m_tx_buffer[m_command_step] = Truncate8(m_button_state >> 8);
if (m_dualshock_enabled)
{
SetMotorStateForConfigIndex(rumble_index, data_in);
}
else
if (m_command_step >= 2 && m_command_step < 7)
{
bool legacy_rumble_on = (m_rx_buffer[2] & 0xC0) == 0x40 && (m_rx_buffer[3] & 0x01) != 0;
const u8 motor_to_set = m_rumble_config[m_command_step - 2];
if (motor_to_set <= LargeMotor)
SetMotorState(motor_to_set, data_in);
}
}
else if (m_command_step == 3)
{
const 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;
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))
{
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:
{
int rumble_index = m_command_step - 2;
if (rumble_index >= 0)
if (m_command_step >= 2 && m_command_step < 7)
{
m_tx_buffer[m_command_step] = m_rumble_config[rumble_index];
m_rumble_config[rumble_index] = data_in;
const u8 index = m_command_step - 2;
m_tx_buffer[m_command_step] = m_rumble_config[index];
m_rumble_config[index] = data_in;
if (data_in == 0x00)
m_rumble_config_small_motor_index = rumble_index;
else if (data_in == 0x01)
m_rumble_config_large_motor_index = rumble_index;
if (data_in == LargeMotor)
WARNING_LOG("Large mapped to byte index {}", index);
else if (data_in == SmallMotor)
WARNING_LOG("Small mapped to byte index {}", index);
}
if (m_command_step == 7)
else if (m_command_step == 7)
{
if (m_rumble_config_large_motor_index == -1)
SetMotorState(LargeMotor, 0);
if (m_rumble_config_small_motor_index == -1)
// reset motor value if we're no longer mapping it
bool has_small = false;
bool has_large = false;
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);
if (!has_large)
SetMotorState(LargeMotor, 0);
}
}
break;
@ -813,14 +759,14 @@ std::unique_ptr<AnalogController> AnalogController::Create(u32 index)
static const Controller::ControllerBindingInfo s_binding_info[] = {
#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) \
{ \
name, display_name, icon_name, static_cast<u32>(AnalogController::Button::Count) + static_cast<u32>(halfaxis), \
InputBindingInfo::Type::HalfAxis, genb \
}
{name, \
display_name, \
icon_name, \
static_cast<u32>(AnalogController::Button::Count) + static_cast<u32>(halfaxis), \
InputBindingInfo::Type::HalfAxis, \
genb}
// clang-format off
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;
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
static constexpr u32 MAX_RESPONSE_LENGTH = 8;
std::array<u8, MAX_RESPONSE_LENGTH> m_rx_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)
u8 GetResponseNumHalfwords() const;
@ -123,7 +123,7 @@ private:
void UpdateHostVibration();
u8 GetExtraButtonMaskLSB() const;
void ResetRumbleConfig();
void SetMotorStateForConfigIndex(int index, u8 value);
void Poll();
float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f;
@ -143,13 +143,11 @@ private:
enum : u8
{
LargeMotor = 0,
SmallMotor = 1
SmallMotor = 0,
LargeMotor = 1,
};
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;
u8 m_status_byte = 0;
@ -164,8 +162,4 @@ private:
// both directions of axis state, merged to m_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"
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_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);