Skip to content

Commit

Permalink
DualShockUDPClient: add motors for rumble
Browse files Browse the repository at this point in the history
  • Loading branch information
breeze2 committed Mar 2, 2023
1 parent 72b22ef commit a0cfc9c
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 3 deletions.
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

0 comments on commit a0cfc9c

Please sign in to comment.