diff options
Diffstat (limited to 'src/input_common/udp/client.cpp')
| -rw-r--r-- | src/input_common/udp/client.cpp | 147 |
1 files changed, 72 insertions, 75 deletions
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index df73f9ff7..e72df924b 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp | |||
| @@ -27,11 +27,9 @@ class Socket { | |||
| 27 | public: | 27 | public: |
| 28 | using clock = std::chrono::system_clock; | 28 | using clock = std::chrono::system_clock; |
| 29 | 29 | ||
| 30 | explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, | 30 | explicit Socket(const std::string& host, u16 port, SocketCallback callback_) |
| 31 | SocketCallback callback_) | ||
| 32 | : callback(std::move(callback_)), timer(io_service), | 31 | : callback(std::move(callback_)), timer(io_service), |
| 33 | socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), | 32 | socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) { |
| 34 | pad_index(pad_index_) { | ||
| 35 | boost::system::error_code ec{}; | 33 | boost::system::error_code ec{}; |
| 36 | auto ipv4 = boost::asio::ip::make_address_v4(host, ec); | 34 | auto ipv4 = boost::asio::ip::make_address_v4(host, ec); |
| 37 | if (ec.value() != boost::system::errc::success) { | 35 | if (ec.value() != boost::system::errc::success) { |
| @@ -99,15 +97,15 @@ private: | |||
| 99 | void HandleSend(const boost::system::error_code&) { | 97 | void HandleSend(const boost::system::error_code&) { |
| 100 | boost::system::error_code _ignored{}; | 98 | boost::system::error_code _ignored{}; |
| 101 | // Send a request for getting port info for the pad | 99 | // Send a request for getting port info for the pad |
| 102 | const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}}; | 100 | const Request::PortInfo port_info{4, {0, 1, 2, 3}}; |
| 103 | const auto port_message = Request::Create(port_info, client_id); | 101 | const auto port_message = Request::Create(port_info, client_id); |
| 104 | std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); | 102 | std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); |
| 105 | socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); | 103 | socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); |
| 106 | 104 | ||
| 107 | // Send a request for getting pad data for the pad | 105 | // Send a request for getting pad data for the pad |
| 108 | const Request::PadData pad_data{ | 106 | const Request::PadData pad_data{ |
| 109 | Request::PadData::Flags::Id, | 107 | Request::PadData::Flags::AllPorts, |
| 110 | static_cast<u8>(pad_index), | 108 | 0, |
| 111 | EMPTY_MAC_ADDRESS, | 109 | EMPTY_MAC_ADDRESS, |
| 112 | }; | 110 | }; |
| 113 | const auto pad_message = Request::Create(pad_data, client_id); | 111 | const auto pad_message = Request::Create(pad_data, client_id); |
| @@ -122,7 +120,6 @@ private: | |||
| 122 | udp::socket socket; | 120 | udp::socket socket; |
| 123 | 121 | ||
| 124 | const u32 client_id; | 122 | const u32 client_id; |
| 125 | std::size_t pad_index{}; | ||
| 126 | 123 | ||
| 127 | static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); | 124 | static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); |
| 128 | static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); | 125 | static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); |
| @@ -150,34 +147,32 @@ Client::~Client() { | |||
| 150 | Reset(); | 147 | Reset(); |
| 151 | } | 148 | } |
| 152 | 149 | ||
| 153 | Client::ClientData::ClientData() = default; | 150 | Client::ClientConnection::ClientConnection() = default; |
| 154 | 151 | ||
| 155 | Client::ClientData::~ClientData() = default; | 152 | Client::ClientConnection::~ClientConnection() = default; |
| 156 | 153 | ||
| 157 | std::vector<Common::ParamPackage> Client::GetInputDevices() const { | 154 | std::vector<Common::ParamPackage> Client::GetInputDevices() const { |
| 158 | std::vector<Common::ParamPackage> devices; | 155 | std::vector<Common::ParamPackage> devices; |
| 159 | for (std::size_t client = 0; client < clients.size(); client++) { | 156 | for (std::size_t pad = 0; pad < pads.size(); pad++) { |
| 160 | if (!DeviceConnected(client)) { | 157 | if (!DeviceConnected(pad)) { |
| 161 | continue; | 158 | continue; |
| 162 | } | 159 | } |
| 163 | std::string name = fmt::format("UDP Controller {}", client); | 160 | std::string name = fmt::format("UDP Controller {}", pad); |
| 164 | devices.emplace_back(Common::ParamPackage{ | 161 | devices.emplace_back(Common::ParamPackage{ |
| 165 | {"class", "cemuhookudp"}, | 162 | {"class", "cemuhookudp"}, |
| 166 | {"display", std::move(name)}, | 163 | {"display", std::move(name)}, |
| 167 | {"port", std::to_string(client)}, | 164 | {"port", std::to_string(pad)}, |
| 168 | }); | 165 | }); |
| 169 | } | 166 | } |
| 170 | return devices; | 167 | return devices; |
| 171 | } | 168 | } |
| 172 | 169 | ||
| 173 | bool Client::DeviceConnected(std::size_t client) const { | 170 | bool Client::DeviceConnected(std::size_t pad) const { |
| 174 | // Use last timestamp to detect if the socket has stopped sending data | 171 | // Use last timestamp to detect if the socket has stopped sending data |
| 175 | const auto now = std::chrono::steady_clock::now(); | 172 | const auto now = std::chrono::steady_clock::now(); |
| 176 | const auto time_difference = | 173 | const auto time_difference = static_cast<u64>( |
| 177 | static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>( | 174 | std::chrono::duration_cast<std::chrono::milliseconds>(now - pads[pad].last_update).count()); |
| 178 | now - clients[client].last_motion_update) | 175 | return time_difference < 1000 && pads[pad].connected; |
| 179 | .count()); | ||
| 180 | return time_difference < 1000 && clients[client].active == 1; | ||
| 181 | } | 176 | } |
| 182 | 177 | ||
| 183 | void Client::ReloadSockets() { | 178 | void Client::ReloadSockets() { |
| @@ -202,25 +197,21 @@ void Client::ReloadSockets() { | |||
| 202 | continue; | 197 | continue; |
| 203 | } | 198 | } |
| 204 | 199 | ||
| 205 | for (std::size_t pad = 0; pad < 4; ++pad) { | 200 | const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port); |
| 206 | const std::size_t client_number = | 201 | if (client_number != MAX_UDP_CLIENTS) { |
| 207 | GetClientNumber(udp_input_address, udp_input_port, pad); | 202 | LOG_ERROR(Input, "Duplicated UDP servers found"); |
| 208 | if (client_number != MAX_UDP_CLIENTS) { | 203 | continue; |
| 209 | LOG_ERROR(Input, "Duplicated UDP servers found"); | ||
| 210 | continue; | ||
| 211 | } | ||
| 212 | StartCommunication(client++, udp_input_address, udp_input_port, pad); | ||
| 213 | } | 204 | } |
| 205 | StartCommunication(client++, udp_input_address, udp_input_port); | ||
| 214 | } | 206 | } |
| 215 | } | 207 | } |
| 216 | 208 | ||
| 217 | std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const { | 209 | std::size_t Client::GetClientNumber(std::string_view host, u16 port) const { |
| 218 | for (std::size_t client = 0; client < clients.size(); client++) { | 210 | for (std::size_t client = 0; client < clients.size(); client++) { |
| 219 | if (clients[client].active == -1) { | 211 | if (clients[client].active == -1) { |
| 220 | continue; | 212 | continue; |
| 221 | } | 213 | } |
| 222 | if (clients[client].host == host && clients[client].port == port && | 214 | if (clients[client].host == host && clients[client].port == port) { |
| 223 | clients[client].pad_index == pad) { | ||
| 224 | return client; | 215 | return client; |
| 225 | } | 216 | } |
| 226 | } | 217 | } |
| @@ -236,69 +227,75 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { | |||
| 236 | } | 227 | } |
| 237 | 228 | ||
| 238 | void Client::OnPadData(Response::PadData data, std::size_t client) { | 229 | void Client::OnPadData(Response::PadData data, std::size_t client) { |
| 239 | // Accept packets only for the correct pad | 230 | const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id; |
| 240 | if (static_cast<u8>(clients[client].pad_index) != data.info.id) { | 231 | |
| 232 | if (pad_index >= pads.size()) { | ||
| 233 | LOG_ERROR(Input, "Invalid pad id {}", data.info.id); | ||
| 241 | return; | 234 | return; |
| 242 | } | 235 | } |
| 243 | 236 | ||
| 244 | LOG_TRACE(Input, "PadData packet received"); | 237 | LOG_TRACE(Input, "PadData packet received"); |
| 245 | if (data.packet_counter == clients[client].packet_sequence) { | 238 | if (data.packet_counter == pads[pad_index].packet_sequence) { |
| 246 | LOG_WARNING( | 239 | LOG_WARNING( |
| 247 | Input, | 240 | Input, |
| 248 | "PadData packet dropped because its stale info. Current count: {} Packet count: {}", | 241 | "PadData packet dropped because its stale info. Current count: {} Packet count: {}", |
| 249 | clients[client].packet_sequence, data.packet_counter); | 242 | pads[pad_index].packet_sequence, data.packet_counter); |
| 243 | pads[pad_index].connected = false; | ||
| 250 | return; | 244 | return; |
| 251 | } | 245 | } |
| 252 | clients[client].active = static_cast<s8>(data.info.is_pad_active); | 246 | |
| 253 | clients[client].packet_sequence = data.packet_counter; | 247 | clients[client].active = 1; |
| 248 | pads[pad_index].connected = true; | ||
| 249 | pads[pad_index].packet_sequence = data.packet_counter; | ||
| 250 | |||
| 254 | const auto now = std::chrono::steady_clock::now(); | 251 | const auto now = std::chrono::steady_clock::now(); |
| 255 | const auto time_difference = | 252 | const auto time_difference = static_cast<u64>( |
| 256 | static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( | 253 | std::chrono::duration_cast<std::chrono::microseconds>(now - pads[pad_index].last_update) |
| 257 | now - clients[client].last_motion_update) | 254 | .count()); |
| 258 | .count()); | 255 | pads[pad_index].last_update = now; |
| 259 | clients[client].last_motion_update = now; | 256 | |
| 260 | const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; | 257 | const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; |
| 261 | clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); | 258 | pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); |
| 262 | // Gyroscope values are not it the correct scale from better joy. | 259 | // Gyroscope values are not it the correct scale from better joy. |
| 263 | // Dividing by 312 allows us to make one full turn = 1 turn | 260 | // Dividing by 312 allows us to make one full turn = 1 turn |
| 264 | // This must be a configurable valued called sensitivity | 261 | // This must be a configurable valued called sensitivity |
| 265 | clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f); | 262 | pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f); |
| 266 | clients[client].motion.UpdateRotation(time_difference); | 263 | pads[pad_index].motion.UpdateRotation(time_difference); |
| 267 | clients[client].motion.UpdateOrientation(time_difference); | 264 | pads[pad_index].motion.UpdateOrientation(time_difference); |
| 268 | 265 | ||
| 269 | { | 266 | { |
| 270 | std::lock_guard guard(clients[client].status.update_mutex); | 267 | std::lock_guard guard(pads[pad_index].status.update_mutex); |
| 271 | clients[client].status.motion_status = clients[client].motion.GetMotion(); | 268 | pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion(); |
| 272 | 269 | ||
| 273 | for (std::size_t id = 0; id < data.touch.size(); ++id) { | 270 | for (std::size_t id = 0; id < data.touch.size(); ++id) { |
| 274 | UpdateTouchInput(data.touch[id], client, id); | 271 | UpdateTouchInput(data.touch[id], client, id); |
| 275 | } | 272 | } |
| 276 | 273 | ||
| 277 | if (configuring) { | 274 | if (configuring) { |
| 278 | const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); | 275 | const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope(); |
| 279 | const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); | 276 | const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration(); |
| 280 | UpdateYuzuSettings(client, accelerometer, gyroscope); | 277 | UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope); |
| 281 | } | 278 | } |
| 282 | } | 279 | } |
| 283 | } | 280 | } |
| 284 | 281 | ||
| 285 | void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, | 282 | void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) { |
| 286 | std::size_t pad_index) { | ||
| 287 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, | 283 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, |
| 288 | [this](Response::PortInfo info) { OnPortInfo(info); }, | 284 | [this](Response::PortInfo info) { OnPortInfo(info); }, |
| 289 | [this, client](Response::PadData data) { OnPadData(data, client); }}; | 285 | [this, client](Response::PadData data) { OnPadData(data, client); }}; |
| 290 | LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port, | 286 | LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); |
| 291 | pad_index); | ||
| 292 | clients[client].host = host; | 287 | clients[client].host = host; |
| 293 | clients[client].port = port; | 288 | clients[client].port = port; |
| 294 | clients[client].pad_index = pad_index; | ||
| 295 | clients[client].active = 0; | 289 | clients[client].active = 0; |
| 296 | clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback); | 290 | clients[client].socket = std::make_unique<Socket>(host, port, callback); |
| 297 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; | 291 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; |
| 292 | |||
| 298 | // Set motion parameters | 293 | // Set motion parameters |
| 299 | // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode | 294 | // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode |
| 300 | // Real HW values are unknown, 0.0001 is an approximate to Standard | 295 | // Real HW values are unknown, 0.0001 is an approximate to Standard |
| 301 | clients[client].motion.SetGyroThreshold(0.0001f); | 296 | for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) { |
| 297 | pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f); | ||
| 298 | } | ||
| 302 | } | 299 | } |
| 303 | 300 | ||
| 304 | void Client::Reset() { | 301 | void Client::Reset() { |
| @@ -311,8 +308,8 @@ void Client::Reset() { | |||
| 311 | } | 308 | } |
| 312 | } | 309 | } |
| 313 | 310 | ||
| 314 | void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 311 | void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index, |
| 315 | const Common::Vec3<float>& gyro) { | 312 | const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro) { |
| 316 | if (gyro.Length() > 0.2f) { | 313 | if (gyro.Length() > 0.2f) { |
| 317 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, | 314 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, |
| 318 | gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); | 315 | gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); |
| @@ -320,7 +317,7 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a | |||
| 320 | UDPPadStatus pad{ | 317 | UDPPadStatus pad{ |
| 321 | .host = clients[client].host, | 318 | .host = clients[client].host, |
| 322 | .port = clients[client].port, | 319 | .port = clients[client].port, |
| 323 | .pad_index = clients[client].pad_index, | 320 | .pad_index = pad_index, |
| 324 | }; | 321 | }; |
| 325 | for (std::size_t i = 0; i < 3; ++i) { | 322 | for (std::size_t i = 0; i < 3; ++i) { |
| 326 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { | 323 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { |
| @@ -391,19 +388,19 @@ void Client::EndConfiguration() { | |||
| 391 | } | 388 | } |
| 392 | 389 | ||
| 393 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { | 390 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { |
| 394 | const std::size_t client_number = GetClientNumber(host, port, pad); | 391 | const std::size_t client_number = GetClientNumber(host, port); |
| 395 | if (client_number == MAX_UDP_CLIENTS) { | 392 | if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { |
| 396 | return clients[0].status; | 393 | return pads[0].status; |
| 397 | } | 394 | } |
| 398 | return clients[client_number].status; | 395 | return pads[(client_number * PADS_PER_CLIENT) + pad].status; |
| 399 | } | 396 | } |
| 400 | 397 | ||
| 401 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { | 398 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { |
| 402 | const std::size_t client_number = GetClientNumber(host, port, pad); | 399 | const std::size_t client_number = GetClientNumber(host, port); |
| 403 | if (client_number == MAX_UDP_CLIENTS) { | 400 | if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { |
| 404 | return clients[0].status; | 401 | return pads[0].status; |
| 405 | } | 402 | } |
| 406 | return clients[client_number].status; | 403 | return pads[(client_number * PADS_PER_CLIENT) + pad].status; |
| 407 | } | 404 | } |
| 408 | 405 | ||
| 409 | Input::TouchStatus& Client::GetTouchState() { | 406 | Input::TouchStatus& Client::GetTouchState() { |
| @@ -422,7 +419,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const { | |||
| 422 | return pad_queue; | 419 | return pad_queue; |
| 423 | } | 420 | } |
| 424 | 421 | ||
| 425 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, | 422 | void TestCommunication(const std::string& host, u16 port, |
| 426 | const std::function<void()>& success_callback, | 423 | const std::function<void()>& success_callback, |
| 427 | const std::function<void()>& failure_callback) { | 424 | const std::function<void()>& failure_callback) { |
| 428 | std::thread([=] { | 425 | std::thread([=] { |
| @@ -432,9 +429,10 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, | |||
| 432 | .port_info = [](Response::PortInfo) {}, | 429 | .port_info = [](Response::PortInfo) {}, |
| 433 | .pad_data = [&](Response::PadData) { success_event.Set(); }, | 430 | .pad_data = [&](Response::PadData) { success_event.Set(); }, |
| 434 | }; | 431 | }; |
| 435 | Socket socket{host, port, pad_index, std::move(callback)}; | 432 | Socket socket{host, port, std::move(callback)}; |
| 436 | std::thread worker_thread{SocketLoop, &socket}; | 433 | std::thread worker_thread{SocketLoop, &socket}; |
| 437 | const bool result = success_event.WaitFor(std::chrono::seconds(5)); | 434 | const bool result = |
| 435 | success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10)); | ||
| 438 | socket.Stop(); | 436 | socket.Stop(); |
| 439 | worker_thread.join(); | 437 | worker_thread.join(); |
| 440 | if (result) { | 438 | if (result) { |
| @@ -446,8 +444,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, | |||
| 446 | } | 444 | } |
| 447 | 445 | ||
| 448 | CalibrationConfigurationJob::CalibrationConfigurationJob( | 446 | CalibrationConfigurationJob::CalibrationConfigurationJob( |
| 449 | const std::string& host, u16 port, std::size_t pad_index, | 447 | const std::string& host, u16 port, std::function<void(Status)> status_callback, |
| 450 | std::function<void(Status)> status_callback, | ||
| 451 | std::function<void(u16, u16, u16, u16)> data_callback) { | 448 | std::function<void(u16, u16, u16, u16)> data_callback) { |
| 452 | 449 | ||
| 453 | std::thread([=, this] { | 450 | std::thread([=, this] { |
| @@ -491,7 +488,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 491 | complete_event.Set(); | 488 | complete_event.Set(); |
| 492 | } | 489 | } |
| 493 | }}; | 490 | }}; |
| 494 | Socket socket{host, port, pad_index, std::move(callback)}; | 491 | Socket socket{host, port, std::move(callback)}; |
| 495 | std::thread worker_thread{SocketLoop, &socket}; | 492 | std::thread worker_thread{SocketLoop, &socket}; |
| 496 | complete_event.Wait(); | 493 | complete_event.Wait(); |
| 497 | socket.Stop(); | 494 | socket.Stop(); |