summaryrefslogtreecommitdiff
path: root/src/input_common/udp/client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/udp/client.cpp')
-rw-r--r--src/input_common/udp/client.cpp148
1 files changed, 94 insertions, 54 deletions
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 412d57896..df73f9ff7 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -5,6 +5,7 @@
5#include <chrono> 5#include <chrono>
6#include <cstring> 6#include <cstring>
7#include <functional> 7#include <functional>
8#include <random>
8#include <thread> 9#include <thread>
9#include <boost/asio.hpp> 10#include <boost/asio.hpp>
10#include "common/logging/log.h" 11#include "common/logging/log.h"
@@ -26,10 +27,10 @@ class Socket {
26public: 27public:
27 using clock = std::chrono::system_clock; 28 using clock = std::chrono::system_clock;
28 29
29 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_, 30 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_,
30 SocketCallback callback_) 31 SocketCallback callback_)
31 : callback(std::move(callback_)), timer(io_service), 32 : callback(std::move(callback_)), timer(io_service),
32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_), 33 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()),
33 pad_index(pad_index_) { 34 pad_index(pad_index_) {
34 boost::system::error_code ec{}; 35 boost::system::error_code ec{};
35 auto ipv4 = boost::asio::ip::make_address_v4(host, ec); 36 auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
@@ -63,6 +64,11 @@ public:
63 } 64 }
64 65
65private: 66private:
67 u32 GenerateRandomClientId() const {
68 std::random_device device;
69 return device();
70 }
71
66 void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { 72 void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) {
67 if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { 73 if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) {
68 switch (*type) { 74 switch (*type) {
@@ -115,7 +121,7 @@ private:
115 boost::asio::basic_waitable_timer<clock> timer; 121 boost::asio::basic_waitable_timer<clock> timer;
116 udp::socket socket; 122 udp::socket socket;
117 123
118 u32 client_id{}; 124 const u32 client_id;
119 std::size_t pad_index{}; 125 std::size_t pad_index{};
120 126
121 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); 127 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
@@ -136,6 +142,7 @@ static void SocketLoop(Socket* socket) {
136 142
137Client::Client() { 143Client::Client() {
138 LOG_INFO(Input, "Udp Initialization started"); 144 LOG_INFO(Input, "Udp Initialization started");
145 finger_id.fill(MAX_TOUCH_FINGERS);
139 ReloadSockets(); 146 ReloadSockets();
140} 147}
141 148
@@ -143,6 +150,10 @@ Client::~Client() {
143 Reset(); 150 Reset();
144} 151}
145 152
153Client::ClientData::ClientData() = default;
154
155Client::ClientData::~ClientData() = default;
156
146std::vector<Common::ParamPackage> Client::GetInputDevices() const { 157std::vector<Common::ParamPackage> Client::GetInputDevices() const {
147 std::vector<Common::ParamPackage> devices; 158 std::vector<Common::ParamPackage> devices;
148 for (std::size_t client = 0; client < clients.size(); client++) { 159 for (std::size_t client = 0; client < clients.size(); client++) {
@@ -176,7 +187,7 @@ void Client::ReloadSockets() {
176 std::string server_token; 187 std::string server_token;
177 std::size_t client = 0; 188 std::size_t client = 0;
178 while (std::getline(servers_ss, server_token, ',')) { 189 while (std::getline(servers_ss, server_token, ',')) {
179 if (client == max_udp_clients) { 190 if (client == MAX_UDP_CLIENTS) {
180 break; 191 break;
181 } 192 }
182 std::stringstream server_ss(server_token); 193 std::stringstream server_ss(server_token);
@@ -194,11 +205,11 @@ void Client::ReloadSockets() {
194 for (std::size_t pad = 0; pad < 4; ++pad) { 205 for (std::size_t pad = 0; pad < 4; ++pad) {
195 const std::size_t client_number = 206 const std::size_t client_number =
196 GetClientNumber(udp_input_address, udp_input_port, pad); 207 GetClientNumber(udp_input_address, udp_input_port, pad);
197 if (client_number != max_udp_clients) { 208 if (client_number != MAX_UDP_CLIENTS) {
198 LOG_ERROR(Input, "Duplicated UDP servers found"); 209 LOG_ERROR(Input, "Duplicated UDP servers found");
199 continue; 210 continue;
200 } 211 }
201 StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872); 212 StartCommunication(client++, udp_input_address, udp_input_port, pad);
202 } 213 }
203 } 214 }
204} 215}
@@ -213,7 +224,7 @@ std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t
213 return client; 224 return client;
214 } 225 }
215 } 226 }
216 return max_udp_clients; 227 return MAX_UDP_CLIENTS;
217} 228}
218 229
219void Client::OnVersion([[maybe_unused]] Response::Version data) { 230void Client::OnVersion([[maybe_unused]] Response::Version data) {
@@ -259,39 +270,20 @@ void Client::OnPadData(Response::PadData data, std::size_t client) {
259 std::lock_guard guard(clients[client].status.update_mutex); 270 std::lock_guard guard(clients[client].status.update_mutex);
260 clients[client].status.motion_status = clients[client].motion.GetMotion(); 271 clients[client].status.motion_status = clients[client].motion.GetMotion();
261 272
262 // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates 273 for (std::size_t id = 0; id < data.touch.size(); ++id) {
263 // between a simple "tap" and a hard press that causes the touch screen to click. 274 UpdateTouchInput(data.touch[id], client, id);
264 const bool is_active = data.touch_1.is_active != 0;
265
266 float x = 0;
267 float y = 0;
268
269 if (is_active && clients[client].status.touch_calibration) {
270 const u16 min_x = clients[client].status.touch_calibration->min_x;
271 const u16 max_x = clients[client].status.touch_calibration->max_x;
272 const u16 min_y = clients[client].status.touch_calibration->min_y;
273 const u16 max_y = clients[client].status.touch_calibration->max_y;
274
275 x = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) -
276 min_x) /
277 static_cast<float>(max_x - min_x);
278 y = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) -
279 min_y) /
280 static_cast<float>(max_y - min_y);
281 } 275 }
282 276
283 clients[client].status.touch_status = {x, y, is_active};
284
285 if (configuring) { 277 if (configuring) {
286 const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); 278 const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
287 const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); 279 const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
288 UpdateYuzuSettings(client, accelerometer, gyroscope, is_active); 280 UpdateYuzuSettings(client, accelerometer, gyroscope);
289 } 281 }
290 } 282 }
291} 283}
292 284
293void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, 285void Client::StartCommunication(std::size_t client, const std::string& host, u16 port,
294 std::size_t pad_index, u32 client_id) { 286 std::size_t pad_index) {
295 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 287 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
296 [this](Response::PortInfo info) { OnPortInfo(info); }, 288 [this](Response::PortInfo info) { OnPortInfo(info); },
297 [this, client](Response::PadData data) { OnPadData(data, client); }}; 289 [this, client](Response::PadData data) { OnPadData(data, client); }};
@@ -301,7 +293,7 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16
301 clients[client].port = port; 293 clients[client].port = port;
302 clients[client].pad_index = pad_index; 294 clients[client].pad_index = pad_index;
303 clients[client].active = 0; 295 clients[client].active = 0;
304 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); 296 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback);
305 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; 297 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
306 // Set motion parameters 298 // Set motion parameters
307 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode 299 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
@@ -320,21 +312,17 @@ void Client::Reset() {
320} 312}
321 313
322void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 314void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
323 const Common::Vec3<float>& gyro, bool touch) { 315 const Common::Vec3<float>& gyro) {
324 if (gyro.Length() > 0.2f) { 316 if (gyro.Length() > 0.2f) {
325 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", 317 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client,
326 client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); 318 gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]);
327 } 319 }
328 UDPPadStatus pad{ 320 UDPPadStatus pad{
329 .host = clients[client].host, 321 .host = clients[client].host,
330 .port = clients[client].port, 322 .port = clients[client].port,
331 .pad_index = clients[client].pad_index, 323 .pad_index = clients[client].pad_index,
332 }; 324 };
333 if (touch) { 325 for (std::size_t i = 0; i < 3; ++i) {
334 pad.touch = PadTouch::Click;
335 pad_queue.Push(pad);
336 }
337 for (size_t i = 0; i < 3; ++i) {
338 if (gyro[i] > 5.0f || gyro[i] < -5.0f) { 326 if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
339 pad.motion = static_cast<PadMotion>(i); 327 pad.motion = static_cast<PadMotion>(i);
340 pad.motion_value = gyro[i]; 328 pad.motion_value = gyro[i];
@@ -348,6 +336,50 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a
348 } 336 }
349} 337}
350 338
339std::optional<std::size_t> Client::GetUnusedFingerID() const {
340 std::size_t first_free_id = 0;
341 while (first_free_id < MAX_TOUCH_FINGERS) {
342 if (!std::get<2>(touch_status[first_free_id])) {
343 return first_free_id;
344 } else {
345 first_free_id++;
346 }
347 }
348 return std::nullopt;
349}
350
351void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) {
352 // TODO: Use custom calibration per device
353 const Common::ParamPackage touch_param(Settings::values.touch_device);
354 const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100));
355 const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50));
356 const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800));
357 const u16 max_y = static_cast<u16>(touch_param.Get("max_y", 850));
358 const std::size_t touch_id = client * 2 + id;
359 if (touch_pad.is_active) {
360 if (finger_id[touch_id] == MAX_TOUCH_FINGERS) {
361 const auto first_free_id = GetUnusedFingerID();
362 if (!first_free_id) {
363 // Invalid finger id skip to next input
364 return;
365 }
366 finger_id[touch_id] = *first_free_id;
367 }
368 auto& [x, y, pressed] = touch_status[finger_id[touch_id]];
369 x = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.x), min_x, max_x) - min_x) /
370 static_cast<float>(max_x - min_x);
371 y = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.y), min_y, max_y) - min_y) /
372 static_cast<float>(max_y - min_y);
373 pressed = true;
374 return;
375 }
376
377 if (finger_id[touch_id] != MAX_TOUCH_FINGERS) {
378 touch_status[finger_id[touch_id]] = {};
379 finger_id[touch_id] = MAX_TOUCH_FINGERS;
380 }
381}
382
351void Client::BeginConfiguration() { 383void Client::BeginConfiguration() {
352 pad_queue.Clear(); 384 pad_queue.Clear();
353 configuring = true; 385 configuring = true;
@@ -360,7 +392,7 @@ void Client::EndConfiguration() {
360 392
361DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { 393DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
362 const std::size_t client_number = GetClientNumber(host, port, pad); 394 const std::size_t client_number = GetClientNumber(host, port, pad);
363 if (client_number == max_udp_clients) { 395 if (client_number == MAX_UDP_CLIENTS) {
364 return clients[0].status; 396 return clients[0].status;
365 } 397 }
366 return clients[client_number].status; 398 return clients[client_number].status;
@@ -368,12 +400,20 @@ DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t
368 400
369const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { 401const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
370 const std::size_t client_number = GetClientNumber(host, port, pad); 402 const std::size_t client_number = GetClientNumber(host, port, pad);
371 if (client_number == max_udp_clients) { 403 if (client_number == MAX_UDP_CLIENTS) {
372 return clients[0].status; 404 return clients[0].status;
373 } 405 }
374 return clients[client_number].status; 406 return clients[client_number].status;
375} 407}
376 408
409Input::TouchStatus& Client::GetTouchState() {
410 return touch_status;
411}
412
413const Input::TouchStatus& Client::GetTouchState() const {
414 return touch_status;
415}
416
377Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { 417Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() {
378 return pad_queue; 418 return pad_queue;
379} 419}
@@ -382,7 +422,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
382 return pad_queue; 422 return pad_queue;
383} 423}
384 424
385void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 425void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
386 const std::function<void()>& success_callback, 426 const std::function<void()>& success_callback,
387 const std::function<void()>& failure_callback) { 427 const std::function<void()>& failure_callback) {
388 std::thread([=] { 428 std::thread([=] {
@@ -392,7 +432,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
392 .port_info = [](Response::PortInfo) {}, 432 .port_info = [](Response::PortInfo) {},
393 .pad_data = [&](Response::PadData) { success_event.Set(); }, 433 .pad_data = [&](Response::PadData) { success_event.Set(); },
394 }; 434 };
395 Socket socket{host, port, pad_index, client_id, std::move(callback)}; 435 Socket socket{host, port, pad_index, std::move(callback)};
396 std::thread worker_thread{SocketLoop, &socket}; 436 std::thread worker_thread{SocketLoop, &socket};
397 const bool result = success_event.WaitFor(std::chrono::seconds(5)); 437 const bool result = success_event.WaitFor(std::chrono::seconds(5));
398 socket.Stop(); 438 socket.Stop();
@@ -406,7 +446,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
406} 446}
407 447
408CalibrationConfigurationJob::CalibrationConfigurationJob( 448CalibrationConfigurationJob::CalibrationConfigurationJob(
409 const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 449 const std::string& host, u16 port, std::size_t pad_index,
410 std::function<void(Status)> status_callback, 450 std::function<void(Status)> status_callback,
411 std::function<void(u16, u16, u16, u16)> data_callback) { 451 std::function<void(u16, u16, u16, u16)> data_callback) {
412 452
@@ -426,24 +466,24 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
426 current_status = Status::Ready; 466 current_status = Status::Ready;
427 status_callback(current_status); 467 status_callback(current_status);
428 } 468 }
429 if (data.touch_1.is_active == 0) { 469 if (data.touch[0].is_active == 0) {
430 return; 470 return;
431 } 471 }
432 LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, 472 LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x,
433 data.touch_1.y); 473 data.touch[0].y);
434 min_x = std::min(min_x, static_cast<u16>(data.touch_1.x)); 474 min_x = std::min(min_x, static_cast<u16>(data.touch[0].x));
435 min_y = std::min(min_y, static_cast<u16>(data.touch_1.y)); 475 min_y = std::min(min_y, static_cast<u16>(data.touch[0].y));
436 if (current_status == Status::Ready) { 476 if (current_status == Status::Ready) {
437 // First touch - min data (min_x/min_y) 477 // First touch - min data (min_x/min_y)
438 current_status = Status::Stage1Completed; 478 current_status = Status::Stage1Completed;
439 status_callback(current_status); 479 status_callback(current_status);
440 } 480 }
441 if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD && 481 if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
442 data.touch_1.y - min_y > CALIBRATION_THRESHOLD) { 482 data.touch[0].y - min_y > CALIBRATION_THRESHOLD) {
443 // Set the current position as max value and finishes 483 // Set the current position as max value and finishes
444 // configuration 484 // configuration
445 max_x = data.touch_1.x; 485 max_x = data.touch[0].x;
446 max_y = data.touch_1.y; 486 max_y = data.touch[0].y;
447 current_status = Status::Completed; 487 current_status = Status::Completed;
448 data_callback(min_x, min_y, max_x, max_y); 488 data_callback(min_x, min_y, max_x, max_y);
449 status_callback(current_status); 489 status_callback(current_status);
@@ -451,7 +491,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
451 complete_event.Set(); 491 complete_event.Set();
452 } 492 }
453 }}; 493 }};
454 Socket socket{host, port, pad_index, client_id, std::move(callback)}; 494 Socket socket{host, port, pad_index, std::move(callback)};
455 std::thread worker_thread{SocketLoop, &socket}; 495 std::thread worker_thread{SocketLoop, &socket};
456 complete_event.Wait(); 496 complete_event.Wait();
457 socket.Stop(); 497 socket.Stop();