Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DualShockUDPClient: add motors for rumble #11545

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,32 @@ class Device final : public Core::Device
const BatteryState& m_battery;
};

class Motor final : public Output
{
public:
Motor(u8 index, Device* parent) : m_index(index), m_parent(parent) {}
std::string GetName() const override
{
std::ostringstream ss;
ss << "Motor " << static_cast<int>(m_index);
return ss.str();
}
void SetState(ControlState state) override
{
m_state = state;
m_parent->UpdateMotor(m_index, m_state);
}

private:
const u8 m_index;
Device* m_parent;
ControlState m_state;
};

public:
void UpdateInput() override;
void QueryMotorCount();
void UpdateMotor(u8 motor_id, ControlState motor_state);

Device(std::string name, int index, std::string server_address, u16 server_port, u32 client_uid);

Expand All @@ -152,6 +176,7 @@ class Device final : public Core::Device
int m_touch_y = 0;
const std::string m_server_address;
const u16 m_server_port;
int m_motor_count = -1;

s16 m_touch_x_min;
s16 m_touch_y_min;
Expand Down Expand Up @@ -220,6 +245,7 @@ class InputBackend final : public ciface::InputBackend
std::thread m_hotplug_thread;
Common::Flag m_hotplug_thread_running;
std::size_t m_config_change_callback_id;
std::vector<std::shared_ptr<Device>> m_devices;
};

std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface)
Expand Down Expand Up @@ -270,6 +296,11 @@ void InputBackend::HotplugThreadFunc()
}
timed_out_servers[i] = true;
}

for (const auto& d : m_devices)
{
d->QueryMotorCount();
}
}

sf::SocketSelector selector;
Expand Down Expand Up @@ -491,6 +522,7 @@ void InputBackend::PopulateDevices()
// correctly if they have the same name
GetControllerInterface().RemoveDevice(
[](const auto* dev) { return dev->GetSource() == DUALSHOCKUDP_SOURCE_NAME; });
m_devices.clear();

// Users might have created more than one server on the same IP/Port.
// Devices might end up being duplicated (if the server responds two all requests)
Expand All @@ -503,9 +535,10 @@ void InputBackend::PopulateDevices()
if (port_info.pad_state != Proto::DsState::Connected)
continue;

GetControllerInterface().AddDevice(
std::make_shared<Device>(server.m_description, static_cast<int>(port_index),
server.m_address, server.m_port, m_client_uid));
const auto device = std::make_shared<Device>(server.m_description, static_cast<int>(port_index),
server.m_address, server.m_port, m_client_uid);
m_devices.emplace_back(std::move(device));
GetControllerInterface().AddDevice(device);
}
}
}
Expand Down Expand Up @@ -580,13 +613,18 @@ Device::Device(std::string name, int index, std::string server_address, u16 serv

AddInput(new BatteryInput(m_pad_data.battery_status));

// Two motors for DualShock
AddOutput(new Motor(0, this));
AddOutput(new Motor(1, this));

m_touch_x_min = 0;
m_touch_y_min = 0;
// DS4 touchpad max values
m_touch_x_max = 1919;
m_touch_y_max = 941;

ResetPadData();
QueryMotorCount();
}

void Device::ResetPadData()
Expand Down Expand Up @@ -659,6 +697,50 @@ void Device::UpdateInput()
m_prev_touch = m_pad_data.touch1;
m_prev_touch_valid = true;
}
else if (m_motor_count == -1)
{
if (auto motor_info = msg.CheckAndCastTo<Proto::MessageType::MotorInfoResponse>())
{
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient receive motor count {}",
motor_info->motor_count);
// Update motor count
m_motor_count = motor_info->motor_count;
}
}
}
}

void Device::QueryMotorCount()
{
Proto::Message<Proto::MessageType::MotorInfoRequest> req_msg(m_client_uid);
auto& data_req = req_msg.m_message;
data_req.register_flags = Proto::RegisterFlags::PadID;
data_req.pad_id_to_register = m_index;
req_msg.Finish();
if (m_socket.send(&data_req, sizeof(data_req), m_server_address, m_server_port) !=
sf::Socket::Status::Done)
{
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient QueryMotorCount send failed");
}
}

void Device::UpdateMotor(u8 motor_id, ControlState motor_state)
{
// Only the motor which `id < count` works, id takes value from 0 to `count - 1`
if (motor_id < m_motor_count)
{
Proto::Message<Proto::MessageType::PadRumbleRequest> msg(m_client_uid);
auto& data_req = msg.m_message;
data_req.register_flags = Proto::RegisterFlags::PadID;
data_req.pad_id_to_register = m_index;
data_req.motor_id = motor_id;
data_req.motor_state = motor_state;
msg.Finish();
if (m_socket.send(&data_req, sizeof(data_req), m_server_address, m_server_port) !=
sf::Socket::Status::Done)
{
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient UpdateMotor send failed");
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,45 @@ struct PadDataResponse
float gyro_roll_deg_s;
};

struct MotorInfoRequest
{
static constexpr auto FROM = CLIENT;
static constexpr auto TYPE = 0x110001U;
MessageHeader header;
u32 message_type;
RegisterFlags register_flags;
u8 pad_id_to_register;
std::array<u8, 6> mac_address_to_register;
};

struct MotorInfoResponse
{
static constexpr auto FROM = SERVER;
static constexpr auto TYPE = 0x110001U;
MessageHeader header;
u32 message_type;
u8 pad_id;
DsState pad_state;
DsModel model;
DsConnection connection_type;
std::array<u8, 6> pad_mac_address;
DsBattery battery_status;
u8 motor_count;
};

struct PadRumbleRequest
{
static constexpr auto FROM = CLIENT;
static constexpr auto TYPE = 0x110002U;
MessageHeader header;
u32 message_type;
RegisterFlags register_flags;
u8 pad_id_to_register;
std::array<u8, 6> mac_address_to_register;
u8 motor_id;
ControlState motor_state;
};

struct FromServer
{
union
Expand All @@ -197,6 +236,7 @@ struct FromServer
MessageType::VersionResponse version_response;
MessageType::PortInfo port_info;
MessageType::PadDataResponse pad_data_response;
MessageType::MotorInfoResponse motor_info_response;
};
};

Expand All @@ -212,6 +252,8 @@ struct FromClient
MessageType::VersionRequest version_request;
MessageType::ListPorts list_ports;
MessageType::PadDataRequest pad_data_request;
MessageType::MotorInfoRequest motor_info_request;
MessageType::PadRumbleRequest pad_rumble_request;
};
};
} // namespace MessageType
Expand Down Expand Up @@ -244,6 +286,8 @@ struct Message
m_message.header.crc32 = 0;
const u32 crc32_calculated =
Common::ComputeCRC32(reinterpret_cast<const u8*>(&m_message), sizeof(ToMsgType));
// recover crc32 value
m_message.header.crc32 = crc32_in_header;
if (crc32_in_header != crc32_calculated)
{
NOTICE_LOG_FMT(
Expand Down