summaryrefslogtreecommitdiff
path: root/src/input_common/udp/client.cpp
diff options
context:
space:
mode:
authorGravatar Levi2021-01-10 22:09:56 -0700
committerGravatar Levi2021-01-10 22:09:56 -0700
commit7a3c884e39fccfbb498b855080bffabc9ce2e7f1 (patch)
tree5056f9406dec188439cb0deb87603498243a9412 /src/input_common/udp/client.cpp
parentMore forgetting... duh (diff)
parentMerge pull request #5229 from Morph1984/fullscreen-opt (diff)
downloadyuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.gz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.xz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.zip
Merge remote-tracking branch 'upstream/master' into int-flags
Diffstat (limited to 'src/input_common/udp/client.cpp')
-rw-r--r--src/input_common/udp/client.cpp234
1 files changed, 148 insertions, 86 deletions
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 2b6a68d4b..412d57896 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -26,11 +26,11 @@ class Socket {
26public: 26public:
27 using clock = std::chrono::system_clock; 27 using clock = std::chrono::system_clock;
28 28
29 explicit Socket(const std::string& host, u16 port, u8 pad_index, u32 client_id, 29 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_,
30 SocketCallback callback) 30 SocketCallback callback_)
31 : callback(std::move(callback)), timer(io_service), 31 : callback(std::move(callback_)), timer(io_service),
32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id), 32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_),
33 pad_index(pad_index) { 33 pad_index(pad_index_) {
34 boost::system::error_code ec{}; 34 boost::system::error_code ec{};
35 auto ipv4 = boost::asio::ip::make_address_v4(host, ec); 35 auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
36 if (ec.value() != boost::system::errc::success) { 36 if (ec.value() != boost::system::errc::success) {
@@ -63,7 +63,7 @@ public:
63 } 63 }
64 64
65private: 65private:
66 void HandleReceive(const boost::system::error_code& error, std::size_t bytes_transferred) { 66 void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) {
67 if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { 67 if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) {
68 switch (*type) { 68 switch (*type) {
69 case Type::Version: { 69 case Type::Version: {
@@ -90,16 +90,20 @@ private:
90 StartReceive(); 90 StartReceive();
91 } 91 }
92 92
93 void HandleSend(const boost::system::error_code& error) { 93 void HandleSend(const boost::system::error_code&) {
94 boost::system::error_code _ignored{}; 94 boost::system::error_code _ignored{};
95 // Send a request for getting port info for the pad 95 // Send a request for getting port info for the pad
96 Request::PortInfo port_info{1, {pad_index, 0, 0, 0}}; 96 const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}};
97 const auto port_message = Request::Create(port_info, client_id); 97 const auto port_message = Request::Create(port_info, client_id);
98 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); 98 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
99 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); 99 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
100 100
101 // Send a request for getting pad data for the pad 101 // Send a request for getting pad data for the pad
102 Request::PadData pad_data{Request::PadData::Flags::Id, pad_index, EMPTY_MAC_ADDRESS}; 102 const Request::PadData pad_data{
103 Request::PadData::Flags::Id,
104 static_cast<u8>(pad_index),
105 EMPTY_MAC_ADDRESS,
106 };
103 const auto pad_message = Request::Create(pad_data, client_id); 107 const auto pad_message = Request::Create(pad_data, client_id);
104 std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE); 108 std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE);
105 socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored); 109 socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored);
@@ -112,7 +116,7 @@ private:
112 udp::socket socket; 116 udp::socket socket;
113 117
114 u32 client_id{}; 118 u32 client_id{};
115 u8 pad_index{}; 119 std::size_t pad_index{};
116 120
117 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); 121 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
118 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); 122 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -132,15 +136,7 @@ static void SocketLoop(Socket* socket) {
132 136
133Client::Client() { 137Client::Client() {
134 LOG_INFO(Input, "Udp Initialization started"); 138 LOG_INFO(Input, "Udp Initialization started");
135 for (std::size_t client = 0; client < clients.size(); client++) { 139 ReloadSockets();
136 u8 pad = client % 4;
137 StartCommunication(client, Settings::values.udp_input_address,
138 Settings::values.udp_input_port, pad, 24872);
139 // Set motion parameters
140 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
141 // Real HW values are unknown, 0.0001 is an approximate to Standard
142 clients[client].motion.SetGyroThreshold(0.0001f);
143 }
144} 140}
145 141
146Client::~Client() { 142Client::~Client() {
@@ -163,39 +159,77 @@ std::vector<Common::ParamPackage> Client::GetInputDevices() const {
163 return devices; 159 return devices;
164} 160}
165 161
166bool Client::DeviceConnected(std::size_t pad) const { 162bool Client::DeviceConnected(std::size_t client) const {
167 // Use last timestamp to detect if the socket has stopped sending data 163 // Use last timestamp to detect if the socket has stopped sending data
168 const auto now = std::chrono::system_clock::now(); 164 const auto now = std::chrono::steady_clock::now();
169 u64 time_difference = 165 const auto time_difference =
170 std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update) 166 static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>(
171 .count(); 167 now - clients[client].last_motion_update)
172 return time_difference < 1000 && clients[pad].active == 1; 168 .count());
169 return time_difference < 1000 && clients[client].active == 1;
173} 170}
174 171
175void Client::ReloadUDPClient() { 172void Client::ReloadSockets() {
176 for (std::size_t client = 0; client < clients.size(); client++) { 173 Reset();
177 ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client); 174
175 std::stringstream servers_ss(Settings::values.udp_input_servers);
176 std::string server_token;
177 std::size_t client = 0;
178 while (std::getline(servers_ss, server_token, ',')) {
179 if (client == max_udp_clients) {
180 break;
181 }
182 std::stringstream server_ss(server_token);
183 std::string token;
184 std::getline(server_ss, token, ':');
185 std::string udp_input_address = token;
186 std::getline(server_ss, token, ':');
187 char* temp;
188 const u16 udp_input_port = static_cast<u16>(std::strtol(token.c_str(), &temp, 0));
189 if (*temp != '\0') {
190 LOG_ERROR(Input, "Port number is not valid {}", token);
191 continue;
192 }
193
194 for (std::size_t pad = 0; pad < 4; ++pad) {
195 const std::size_t client_number =
196 GetClientNumber(udp_input_address, udp_input_port, pad);
197 if (client_number != max_udp_clients) {
198 LOG_ERROR(Input, "Duplicated UDP servers found");
199 continue;
200 }
201 StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872);
202 }
178 } 203 }
179} 204}
180void Client::ReloadSocket(const std::string& host, u16 port, u8 pad_index, u32 client_id) { 205
181 // client number must be determined from host / port and pad index 206std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const {
182 std::size_t client = pad_index; 207 for (std::size_t client = 0; client < clients.size(); client++) {
183 clients[client].socket->Stop(); 208 if (clients[client].active == -1) {
184 clients[client].thread.join(); 209 continue;
185 StartCommunication(client, host, port, pad_index, client_id); 210 }
211 if (clients[client].host == host && clients[client].port == port &&
212 clients[client].pad_index == pad) {
213 return client;
214 }
215 }
216 return max_udp_clients;
186} 217}
187 218
188void Client::OnVersion(Response::Version data) { 219void Client::OnVersion([[maybe_unused]] Response::Version data) {
189 LOG_TRACE(Input, "Version packet received: {}", data.version); 220 LOG_TRACE(Input, "Version packet received: {}", data.version);
190} 221}
191 222
192void Client::OnPortInfo(Response::PortInfo data) { 223void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {
193 LOG_TRACE(Input, "PortInfo packet received: {}", data.model); 224 LOG_TRACE(Input, "PortInfo packet received: {}", data.model);
194} 225}
195 226
196void Client::OnPadData(Response::PadData data) { 227void Client::OnPadData(Response::PadData data, std::size_t client) {
197 // client number must be determined from host / port and pad index 228 // Accept packets only for the correct pad
198 std::size_t client = data.info.id; 229 if (static_cast<u8>(clients[client].pad_index) != data.info.id) {
230 return;
231 }
232
199 LOG_TRACE(Input, "PadData packet received"); 233 LOG_TRACE(Input, "PadData packet received");
200 if (data.packet_counter == clients[client].packet_sequence) { 234 if (data.packet_counter == clients[client].packet_sequence) {
201 LOG_WARNING( 235 LOG_WARNING(
@@ -204,14 +238,15 @@ void Client::OnPadData(Response::PadData data) {
204 clients[client].packet_sequence, data.packet_counter); 238 clients[client].packet_sequence, data.packet_counter);
205 return; 239 return;
206 } 240 }
207 clients[client].active = data.info.is_pad_active; 241 clients[client].active = static_cast<s8>(data.info.is_pad_active);
208 clients[client].packet_sequence = data.packet_counter; 242 clients[client].packet_sequence = data.packet_counter;
209 const auto now = std::chrono::system_clock::now(); 243 const auto now = std::chrono::steady_clock::now();
210 u64 time_difference = std::chrono::duration_cast<std::chrono::microseconds>( 244 const auto time_difference =
211 now - clients[client].last_motion_update) 245 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>(
212 .count(); 246 now - clients[client].last_motion_update)
247 .count());
213 clients[client].last_motion_update = now; 248 clients[client].last_motion_update = now;
214 Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; 249 const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
215 clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); 250 clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
216 // Gyroscope values are not it the correct scale from better joy. 251 // Gyroscope values are not it the correct scale from better joy.
217 // Dividing by 312 allows us to make one full turn = 1 turn 252 // Dividing by 312 allows us to make one full turn = 1 turn
@@ -219,14 +254,10 @@ void Client::OnPadData(Response::PadData data) {
219 clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f); 254 clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
220 clients[client].motion.UpdateRotation(time_difference); 255 clients[client].motion.UpdateRotation(time_difference);
221 clients[client].motion.UpdateOrientation(time_difference); 256 clients[client].motion.UpdateOrientation(time_difference);
222 Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
223 Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
224 Common::Vec3f rotation = clients[client].motion.GetRotations();
225 std::array<Common::Vec3f, 3> orientation = clients[client].motion.GetOrientation();
226 257
227 { 258 {
228 std::lock_guard guard(clients[client].status.update_mutex); 259 std::lock_guard guard(clients[client].status.update_mutex);
229 clients[client].status.motion_status = {accelerometer, gyroscope, rotation, orientation}; 260 clients[client].status.motion_status = clients[client].motion.GetMotion();
230 261
231 // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates 262 // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
232 // between a simple "tap" and a hard press that causes the touch screen to click. 263 // between a simple "tap" and a hard press that causes the touch screen to click.
@@ -241,98 +272,129 @@ void Client::OnPadData(Response::PadData data) {
241 const u16 min_y = clients[client].status.touch_calibration->min_y; 272 const u16 min_y = clients[client].status.touch_calibration->min_y;
242 const u16 max_y = clients[client].status.touch_calibration->max_y; 273 const u16 max_y = clients[client].status.touch_calibration->max_y;
243 274
244 x = (std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - min_x) / 275 x = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) -
276 min_x) /
245 static_cast<float>(max_x - min_x); 277 static_cast<float>(max_x - min_x);
246 y = (std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) - min_y) / 278 y = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) -
279 min_y) /
247 static_cast<float>(max_y - min_y); 280 static_cast<float>(max_y - min_y);
248 } 281 }
249 282
250 clients[client].status.touch_status = {x, y, is_active}; 283 clients[client].status.touch_status = {x, y, is_active};
251 284
252 if (configuring) { 285 if (configuring) {
286 const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
287 const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
253 UpdateYuzuSettings(client, accelerometer, gyroscope, is_active); 288 UpdateYuzuSettings(client, accelerometer, gyroscope, is_active);
254 } 289 }
255 } 290 }
256} 291}
257 292
258void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, u8 pad_index, 293void Client::StartCommunication(std::size_t client, const std::string& host, u16 port,
259 u32 client_id) { 294 std::size_t pad_index, u32 client_id) {
260 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 295 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
261 [this](Response::PortInfo info) { OnPortInfo(info); }, 296 [this](Response::PortInfo info) { OnPortInfo(info); },
262 [this](Response::PadData data) { OnPadData(data); }}; 297 [this, client](Response::PadData data) { OnPadData(data, client); }};
263 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); 298 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port,
299 pad_index);
300 clients[client].host = host;
301 clients[client].port = port;
302 clients[client].pad_index = pad_index;
303 clients[client].active = 0;
264 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); 304 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
265 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; 305 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
306 // Set motion parameters
307 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
308 // Real HW values are unknown, 0.0001 is an approximate to Standard
309 clients[client].motion.SetGyroThreshold(0.0001f);
266} 310}
267 311
268void Client::Reset() { 312void Client::Reset() {
269 for (std::size_t client = 0; client < clients.size(); client++) { 313 for (auto& client : clients) {
270 clients[client].socket->Stop(); 314 if (client.thread.joinable()) {
271 clients[client].thread.join(); 315 client.active = -1;
316 client.socket->Stop();
317 client.thread.join();
318 }
272 } 319 }
273} 320}
274 321
275void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 322void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
276 const Common::Vec3<float>& gyro, bool touch) { 323 const Common::Vec3<float>& gyro, bool touch) {
277 UDPPadStatus pad; 324 if (gyro.Length() > 0.2f) {
325 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}",
326 client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch);
327 }
328 UDPPadStatus pad{
329 .host = clients[client].host,
330 .port = clients[client].port,
331 .pad_index = clients[client].pad_index,
332 };
278 if (touch) { 333 if (touch) {
279 pad.touch = PadTouch::Click; 334 pad.touch = PadTouch::Click;
280 pad_queue[client].Push(pad); 335 pad_queue.Push(pad);
281 } 336 }
282 for (size_t i = 0; i < 3; ++i) { 337 for (size_t i = 0; i < 3; ++i) {
283 if (gyro[i] > 6.0f || gyro[i] < -6.0f) { 338 if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
284 pad.motion = static_cast<PadMotion>(i); 339 pad.motion = static_cast<PadMotion>(i);
285 pad.motion_value = gyro[i]; 340 pad.motion_value = gyro[i];
286 pad_queue[client].Push(pad); 341 pad_queue.Push(pad);
287 } 342 }
288 if (acc[i] > 2.0f || acc[i] < -2.0f) { 343 if (acc[i] > 1.75f || acc[i] < -1.75f) {
289 pad.motion = static_cast<PadMotion>(i + 3); 344 pad.motion = static_cast<PadMotion>(i + 3);
290 pad.motion_value = acc[i]; 345 pad.motion_value = acc[i];
291 pad_queue[client].Push(pad); 346 pad_queue.Push(pad);
292 } 347 }
293 } 348 }
294} 349}
295 350
296void Client::BeginConfiguration() { 351void Client::BeginConfiguration() {
297 for (auto& pq : pad_queue) { 352 pad_queue.Clear();
298 pq.Clear();
299 }
300 configuring = true; 353 configuring = true;
301} 354}
302 355
303void Client::EndConfiguration() { 356void Client::EndConfiguration() {
304 for (auto& pq : pad_queue) { 357 pad_queue.Clear();
305 pq.Clear();
306 }
307 configuring = false; 358 configuring = false;
308} 359}
309 360
310DeviceStatus& Client::GetPadState(std::size_t pad) { 361DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
311 return clients[pad].status; 362 const std::size_t client_number = GetClientNumber(host, port, pad);
363 if (client_number == max_udp_clients) {
364 return clients[0].status;
365 }
366 return clients[client_number].status;
312} 367}
313 368
314const DeviceStatus& Client::GetPadState(std::size_t pad) const { 369const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
315 return clients[pad].status; 370 const std::size_t client_number = GetClientNumber(host, port, pad);
371 if (client_number == max_udp_clients) {
372 return clients[0].status;
373 }
374 return clients[client_number].status;
316} 375}
317 376
318std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() { 377Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() {
319 return pad_queue; 378 return pad_queue;
320} 379}
321 380
322const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() const { 381const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
323 return pad_queue; 382 return pad_queue;
324} 383}
325 384
326void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id, 385void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
327 std::function<void()> success_callback, 386 const std::function<void()>& success_callback,
328 std::function<void()> failure_callback) { 387 const std::function<void()>& failure_callback) {
329 std::thread([=] { 388 std::thread([=] {
330 Common::Event success_event; 389 Common::Event success_event;
331 SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, 390 SocketCallback callback{
332 [&](Response::PadData data) { success_event.Set(); }}; 391 .version = [](Response::Version) {},
392 .port_info = [](Response::PortInfo) {},
393 .pad_data = [&](Response::PadData) { success_event.Set(); },
394 };
333 Socket socket{host, port, pad_index, client_id, std::move(callback)}; 395 Socket socket{host, port, pad_index, client_id, std::move(callback)};
334 std::thread worker_thread{SocketLoop, &socket}; 396 std::thread worker_thread{SocketLoop, &socket};
335 bool result = success_event.WaitFor(std::chrono::seconds(8)); 397 const bool result = success_event.WaitFor(std::chrono::seconds(5));
336 socket.Stop(); 398 socket.Stop();
337 worker_thread.join(); 399 worker_thread.join();
338 if (result) { 400 if (result) {
@@ -344,7 +406,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
344} 406}
345 407
346CalibrationConfigurationJob::CalibrationConfigurationJob( 408CalibrationConfigurationJob::CalibrationConfigurationJob(
347 const std::string& host, u16 port, u8 pad_index, u32 client_id, 409 const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
348 std::function<void(Status)> status_callback, 410 std::function<void(Status)> status_callback,
349 std::function<void(u16, u16, u16, u16)> data_callback) { 411 std::function<void(u16, u16, u16, u16)> data_callback) {
350 412
@@ -357,14 +419,14 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
357 u16 max_y{}; 419 u16 max_y{};
358 420
359 Status current_status{Status::Initialized}; 421 Status current_status{Status::Initialized};
360 SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, 422 SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {},
361 [&](Response::PadData data) { 423 [&](Response::PadData data) {
362 if (current_status == Status::Initialized) { 424 if (current_status == Status::Initialized) {
363 // Receiving data means the communication is ready now 425 // Receiving data means the communication is ready now
364 current_status = Status::Ready; 426 current_status = Status::Ready;
365 status_callback(current_status); 427 status_callback(current_status);
366 } 428 }
367 if (!data.touch_1.is_active) { 429 if (data.touch_1.is_active == 0) {
368 return; 430 return;
369 } 431 }
370 LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, 432 LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x,