summaryrefslogtreecommitdiff
path: root/src/input_common/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/helpers')
-rw-r--r--src/input_common/helpers/joycon_driver.cpp245
-rw-r--r--src/input_common/helpers/joycon_driver.h43
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.cpp53
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.h15
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp110
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h44
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp52
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.h41
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp70
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.h22
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h76
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp531
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h74
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.cpp4
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.h4
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.cpp45
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.h14
-rw-r--r--src/input_common/helpers/joycon_protocol/rumble.cpp5
-rw-r--r--src/input_common/helpers/joycon_protocol/rumble.h8
19 files changed, 1041 insertions, 415 deletions
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index 95106f16d..cf51f3481 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -1,7 +1,9 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/scope_exit.h"
5#include "common/swap.h" 7#include "common/swap.h"
6#include "common/thread.h" 8#include "common/thread.h"
7#include "input_common/helpers/joycon_driver.h" 9#include "input_common/helpers/joycon_driver.h"
@@ -27,13 +29,13 @@ void JoyconDriver::Stop() {
27 input_thread = {}; 29 input_thread = {};
28} 30}
29 31
30DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { 32Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
31 std::scoped_lock lock{mutex}; 33 std::scoped_lock lock{mutex};
32 34
33 handle_device_type = ControllerType::None; 35 handle_device_type = ControllerType::None;
34 GetDeviceType(device_info, handle_device_type); 36 GetDeviceType(device_info, handle_device_type);
35 if (handle_device_type == ControllerType::None) { 37 if (handle_device_type == ControllerType::None) {
36 return DriverResult::UnsupportedControllerType; 38 return Common::Input::DriverResult::UnsupportedControllerType;
37 } 39 }
38 40
39 hidapi_handle->handle = 41 hidapi_handle->handle =
@@ -42,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info)
42 if (!hidapi_handle->handle) { 44 if (!hidapi_handle->handle) {
43 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", 45 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
44 device_info->vendor_id, device_info->product_id); 46 device_info->vendor_id, device_info->product_id);
45 return DriverResult::HandleInUse; 47 return Common::Input::DriverResult::HandleInUse;
46 } 48 }
47 SDL_hid_set_nonblocking(hidapi_handle->handle, 1); 49 SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
48 return DriverResult::Success; 50 return Common::Input::DriverResult::Success;
49} 51}
50 52
51DriverResult JoyconDriver::InitializeDevice() { 53Common::Input::DriverResult JoyconDriver::InitializeDevice() {
52 if (!hidapi_handle->handle) { 54 if (!hidapi_handle->handle) {
53 return DriverResult::InvalidHandle; 55 return Common::Input::DriverResult::InvalidHandle;
54 } 56 }
55 std::scoped_lock lock{mutex}; 57 std::scoped_lock lock{mutex};
56 disable_input_thread = true; 58 disable_input_thread = true;
@@ -71,6 +73,7 @@ DriverResult JoyconDriver::InitializeDevice() {
71 nfc_enabled = false; 73 nfc_enabled = false;
72 passive_enabled = false; 74 passive_enabled = false;
73 irs_enabled = false; 75 irs_enabled = false;
76 input_only_device = false;
74 gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; 77 gyro_sensitivity = Joycon::GyroSensitivity::DPS2000;
75 gyro_performance = Joycon::GyroPerformance::HZ833; 78 gyro_performance = Joycon::GyroPerformance::HZ833;
76 accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; 79 accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8;
@@ -85,16 +88,23 @@ DriverResult JoyconDriver::InitializeDevice() {
85 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); 88 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
86 89
87 // Get fixed joycon info 90 // Get fixed joycon info
88 generic_protocol->GetVersionNumber(version); 91 if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) {
89 generic_protocol->SetLowPowerMode(false); 92 // If this command fails the device doesn't accept configuration commands
90 generic_protocol->GetColor(color); 93 input_only_device = true;
91 if (handle_device_type == ControllerType::Pro) { 94 }
92 // Some 3rd party controllers aren't pro controllers 95
93 generic_protocol->GetControllerType(device_type); 96 if (!input_only_device) {
94 } else { 97 generic_protocol->SetLowPowerMode(false);
95 device_type = handle_device_type; 98 generic_protocol->GetColor(color);
99 if (handle_device_type == ControllerType::Pro) {
100 // Some 3rd party controllers aren't pro controllers
101 generic_protocol->GetControllerType(device_type);
102 } else {
103 device_type = handle_device_type;
104 }
105 generic_protocol->GetSerialNumber(serial_number);
96 } 106 }
97 generic_protocol->GetSerialNumber(serial_number); 107
98 supported_features = GetSupportedFeatures(); 108 supported_features = GetSupportedFeatures();
99 109
100 // Get Calibration data 110 // Get Calibration data
@@ -112,7 +122,7 @@ DriverResult JoyconDriver::InitializeDevice() {
112 joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, 122 joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration,
113 right_stick_calibration, motion_calibration); 123 right_stick_calibration, motion_calibration);
114 124
115 // Start pooling for data 125 // Start polling for data
116 is_connected = true; 126 is_connected = true;
117 if (!input_thread_running) { 127 if (!input_thread_running) {
118 input_thread = 128 input_thread =
@@ -120,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() {
120 } 130 }
121 131
122 disable_input_thread = false; 132 disable_input_thread = false;
123 return DriverResult::Success; 133 return Common::Input::DriverResult::Success;
124} 134}
125 135
126void JoyconDriver::InputThread(std::stop_token stop_token) { 136void JoyconDriver::InputThread(std::stop_token stop_token) {
@@ -208,7 +218,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
208 joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); 218 joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat());
209 } 219 }
210 220
211 if (nfc_protocol->IsEnabled()) { 221 if (nfc_protocol->IsPolling()) {
212 if (amiibo_detected) { 222 if (amiibo_detected) {
213 if (!nfc_protocol->HasAmiibo()) { 223 if (!nfc_protocol->HasAmiibo()) {
214 joycon_poller->UpdateAmiibo({}); 224 joycon_poller->UpdateAmiibo({});
@@ -218,10 +228,10 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
218 } 228 }
219 229
220 if (!amiibo_detected) { 230 if (!amiibo_detected) {
221 std::vector<u8> data(0x21C); 231 Joycon::TagInfo tag_info;
222 const auto result = nfc_protocol->ScanAmiibo(data); 232 const auto result = nfc_protocol->GetTagInfo(tag_info);
223 if (result == DriverResult::Success) { 233 if (result == Common::Input::DriverResult::Success) {
224 joycon_poller->UpdateAmiibo(data); 234 joycon_poller->UpdateAmiibo(tag_info);
225 amiibo_detected = true; 235 amiibo_detected = true;
226 } 236 }
227 } 237 }
@@ -246,7 +256,8 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
246 } 256 }
247} 257}
248 258
249DriverResult JoyconDriver::SetPollingMode() { 259Common::Input::DriverResult JoyconDriver::SetPollingMode() {
260 SCOPE_EXIT({ disable_input_thread = false; });
250 disable_input_thread = true; 261 disable_input_thread = true;
251 262
252 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); 263 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration);
@@ -259,6 +270,10 @@ DriverResult JoyconDriver::SetPollingMode() {
259 generic_protocol->EnableImu(false); 270 generic_protocol->EnableImu(false);
260 } 271 }
261 272
273 if (input_only_device) {
274 return Common::Input::DriverResult::NotSupported;
275 }
276
262 if (irs_protocol->IsEnabled()) { 277 if (irs_protocol->IsEnabled()) {
263 irs_protocol->DisableIrs(); 278 irs_protocol->DisableIrs();
264 } 279 }
@@ -275,46 +290,42 @@ DriverResult JoyconDriver::SetPollingMode() {
275 290
276 if (irs_enabled && supported_features.irs) { 291 if (irs_enabled && supported_features.irs) {
277 auto result = irs_protocol->EnableIrs(); 292 auto result = irs_protocol->EnableIrs();
278 if (result == DriverResult::Success) { 293 if (result == Common::Input::DriverResult::Success) {
279 disable_input_thread = false;
280 return result; 294 return result;
281 } 295 }
282 irs_protocol->DisableIrs(); 296 irs_protocol->DisableIrs();
283 LOG_ERROR(Input, "Error enabling IRS"); 297 LOG_ERROR(Input, "Error enabling IRS");
298 return result;
284 } 299 }
285 300
286 if (nfc_enabled && supported_features.nfc) { 301 if (nfc_enabled && supported_features.nfc) {
287 auto result = nfc_protocol->EnableNfc(); 302 auto result = nfc_protocol->EnableNfc();
288 if (result == DriverResult::Success) { 303 if (result == Common::Input::DriverResult::Success) {
289 result = nfc_protocol->StartNFCPollingMode();
290 }
291 if (result == DriverResult::Success) {
292 disable_input_thread = false;
293 return result; 304 return result;
294 } 305 }
295 nfc_protocol->DisableNfc(); 306 nfc_protocol->DisableNfc();
296 LOG_ERROR(Input, "Error enabling NFC"); 307 LOG_ERROR(Input, "Error enabling NFC");
308 return result;
297 } 309 }
298 310
299 if (hidbus_enabled && supported_features.hidbus) { 311 if (hidbus_enabled && supported_features.hidbus) {
300 auto result = ring_protocol->EnableRingCon(); 312 auto result = ring_protocol->EnableRingCon();
301 if (result == DriverResult::Success) { 313 if (result == Common::Input::DriverResult::Success) {
302 result = ring_protocol->StartRingconPolling(); 314 result = ring_protocol->StartRingconPolling();
303 } 315 }
304 if (result == DriverResult::Success) { 316 if (result == Common::Input::DriverResult::Success) {
305 ring_connected = true; 317 ring_connected = true;
306 disable_input_thread = false;
307 return result; 318 return result;
308 } 319 }
309 ring_connected = false; 320 ring_connected = false;
310 ring_protocol->DisableRingCon(); 321 ring_protocol->DisableRingCon();
311 LOG_ERROR(Input, "Error enabling Ringcon"); 322 LOG_ERROR(Input, "Error enabling Ringcon");
323 return result;
312 } 324 }
313 325
314 if (passive_enabled && supported_features.passive) { 326 if (passive_enabled && supported_features.passive) {
315 const auto result = generic_protocol->EnablePassiveMode(); 327 const auto result = generic_protocol->EnablePassiveMode();
316 if (result == DriverResult::Success) { 328 if (result == Common::Input::DriverResult::Success) {
317 disable_input_thread = false;
318 return result; 329 return result;
319 } 330 }
320 LOG_ERROR(Input, "Error enabling passive mode"); 331 LOG_ERROR(Input, "Error enabling passive mode");
@@ -322,13 +333,12 @@ DriverResult JoyconDriver::SetPollingMode() {
322 333
323 // Default Mode 334 // Default Mode
324 const auto result = generic_protocol->EnableActiveMode(); 335 const auto result = generic_protocol->EnableActiveMode();
325 if (result != DriverResult::Success) { 336 if (result != Common::Input::DriverResult::Success) {
326 LOG_ERROR(Input, "Error enabling active mode"); 337 LOG_ERROR(Input, "Error enabling active mode");
327 } 338 }
328 // Switch calls this function after enabling active mode 339 // Switch calls this function after enabling active mode
329 generic_protocol->TriggersElapsed(); 340 generic_protocol->TriggersElapsed();
330 341
331 disable_input_thread = false;
332 return result; 342 return result;
333} 343}
334 344
@@ -339,6 +349,10 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() {
339 .vibration = true, 349 .vibration = true,
340 }; 350 };
341 351
352 if (input_only_device) {
353 return features;
354 }
355
342 if (device_type == ControllerType::Right) { 356 if (device_type == ControllerType::Right) {
343 features.nfc = true; 357 features.nfc = true;
344 features.irs = true; 358 features.irs = true;
@@ -383,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
383 return true; 397 return true;
384} 398}
385 399
386DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { 400Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
387 std::scoped_lock lock{mutex}; 401 std::scoped_lock lock{mutex};
388 if (disable_input_thread) { 402 if (disable_input_thread) {
389 return DriverResult::HandleInUse; 403 return Common::Input::DriverResult::HandleInUse;
390 } 404 }
391 return rumble_protocol->SendVibration(vibration); 405 return rumble_protocol->SendVibration(vibration);
392} 406}
393 407
394DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { 408Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
395 std::scoped_lock lock{mutex}; 409 std::scoped_lock lock{mutex};
396 if (disable_input_thread) { 410 if (disable_input_thread) {
397 return DriverResult::HandleInUse; 411 return Common::Input::DriverResult::HandleInUse;
398 } 412 }
399 return generic_protocol->SetLedPattern(led_pattern); 413 return generic_protocol->SetLedPattern(led_pattern);
400} 414}
401 415
402DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { 416Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
403 std::scoped_lock lock{mutex}; 417 std::scoped_lock lock{mutex};
404 if (disable_input_thread) { 418 if (disable_input_thread) {
405 return DriverResult::HandleInUse; 419 return Common::Input::DriverResult::HandleInUse;
406 } 420 }
407 disable_input_thread = true; 421 disable_input_thread = true;
408 const auto result = irs_protocol->SetIrsConfig(mode_, format_); 422 const auto result = irs_protocol->SetIrsConfig(mode_, format_);
@@ -410,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
410 return result; 424 return result;
411} 425}
412 426
413DriverResult JoyconDriver::SetPassiveMode() { 427Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
414 std::scoped_lock lock{mutex}; 428 std::scoped_lock lock{mutex};
415 motion_enabled = false; 429 motion_enabled = false;
416 hidbus_enabled = false; 430 hidbus_enabled = false;
@@ -420,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() {
420 return SetPollingMode(); 434 return SetPollingMode();
421} 435}
422 436
423DriverResult JoyconDriver::SetActiveMode() { 437Common::Input::DriverResult JoyconDriver::SetActiveMode() {
424 if (is_ring_disabled_by_irs) { 438 if (is_ring_disabled_by_irs) {
425 is_ring_disabled_by_irs = false; 439 is_ring_disabled_by_irs = false;
426 SetActiveMode(); 440 SetActiveMode();
@@ -436,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() {
436 return SetPollingMode(); 450 return SetPollingMode();
437} 451}
438 452
439DriverResult JoyconDriver::SetIrMode() { 453Common::Input::DriverResult JoyconDriver::SetIrMode() {
440 std::scoped_lock lock{mutex}; 454 std::scoped_lock lock{mutex};
441 455
442 if (!supported_features.irs) { 456 if (!supported_features.irs) {
443 return DriverResult::NotSupported; 457 return Common::Input::DriverResult::NotSupported;
444 } 458 }
445 459
446 if (ring_connected) { 460 if (ring_connected) {
@@ -455,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() {
455 return SetPollingMode(); 469 return SetPollingMode();
456} 470}
457 471
458DriverResult JoyconDriver::SetNfcMode() { 472Common::Input::DriverResult JoyconDriver::SetNfcMode() {
459 std::scoped_lock lock{mutex}; 473 std::scoped_lock lock{mutex};
460 474
461 if (!supported_features.nfc) { 475 if (!supported_features.nfc) {
462 return DriverResult::NotSupported; 476 return Common::Input::DriverResult::NotSupported;
463 } 477 }
464 478
465 motion_enabled = true; 479 motion_enabled = true;
@@ -470,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() {
470 return SetPollingMode(); 484 return SetPollingMode();
471} 485}
472 486
473DriverResult JoyconDriver::SetRingConMode() { 487Common::Input::DriverResult JoyconDriver::SetRingConMode() {
474 std::scoped_lock lock{mutex}; 488 std::scoped_lock lock{mutex};
475 489
476 if (!supported_features.hidbus) { 490 if (!supported_features.hidbus) {
477 return DriverResult::NotSupported; 491 return Common::Input::DriverResult::NotSupported;
478 } 492 }
479 493
480 motion_enabled = true; 494 motion_enabled = true;
@@ -486,29 +500,130 @@ DriverResult JoyconDriver::SetRingConMode() {
486 const auto result = SetPollingMode(); 500 const auto result = SetPollingMode();
487 501
488 if (!ring_connected) { 502 if (!ring_connected) {
489 return DriverResult::NoDeviceDetected; 503 return Common::Input::DriverResult::NoDeviceDetected;
504 }
505
506 return result;
507}
508
509Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
510 std::scoped_lock lock{mutex};
511
512 if (!supported_features.nfc) {
513 return Common::Input::DriverResult::NotSupported;
514 }
515 if (!nfc_protocol->IsEnabled()) {
516 return Common::Input::DriverResult::Disabled;
490 } 517 }
491 518
519 disable_input_thread = true;
520 const auto result = nfc_protocol->StartNFCPollingMode();
521 disable_input_thread = false;
522
492 return result; 523 return result;
493} 524}
494 525
495DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { 526Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
496 std::scoped_lock lock{mutex}; 527 std::scoped_lock lock{mutex};
528
529 if (!supported_features.nfc) {
530 return Common::Input::DriverResult::NotSupported;
531 }
532 if (!nfc_protocol->IsEnabled()) {
533 return Common::Input::DriverResult::Disabled;
534 }
535
497 disable_input_thread = true; 536 disable_input_thread = true;
537 const auto result = nfc_protocol->StopNFCPollingMode();
538 disable_input_thread = false;
539
540 if (amiibo_detected) {
541 amiibo_detected = false;
542 joycon_poller->UpdateAmiibo({});
543 }
544
545 return result;
546}
547
548Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
549 std::scoped_lock lock{mutex};
498 550
499 if (!supported_features.nfc) { 551 if (!supported_features.nfc) {
500 return DriverResult::NotSupported; 552 return Common::Input::DriverResult::NotSupported;
501 } 553 }
502 if (!nfc_protocol->IsEnabled()) { 554 if (!nfc_protocol->IsEnabled()) {
503 return DriverResult::Disabled; 555 return Common::Input::DriverResult::Disabled;
504 } 556 }
505 if (!amiibo_detected) { 557 if (!amiibo_detected) {
506 return DriverResult::ErrorWritingData; 558 return Common::Input::DriverResult::ErrorWritingData;
507 } 559 }
508 560
561 out_data.resize(0x21C);
562 disable_input_thread = true;
563 const auto result = nfc_protocol->ReadAmiibo(out_data);
564 disable_input_thread = false;
565
566 return result;
567}
568
569Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
570 std::scoped_lock lock{mutex};
571
572 if (!supported_features.nfc) {
573 return Common::Input::DriverResult::NotSupported;
574 }
575 if (!nfc_protocol->IsEnabled()) {
576 return Common::Input::DriverResult::Disabled;
577 }
578 if (!amiibo_detected) {
579 return Common::Input::DriverResult::ErrorWritingData;
580 }
581
582 disable_input_thread = true;
509 const auto result = nfc_protocol->WriteAmiibo(data); 583 const auto result = nfc_protocol->WriteAmiibo(data);
584 disable_input_thread = false;
585
586 return result;
587}
510 588
589Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
590 std::span<MifareReadData> out_data) {
591 std::scoped_lock lock{mutex};
592
593 if (!supported_features.nfc) {
594 return Common::Input::DriverResult::NotSupported;
595 }
596 if (!nfc_protocol->IsEnabled()) {
597 return Common::Input::DriverResult::Disabled;
598 }
599 if (!amiibo_detected) {
600 return Common::Input::DriverResult::ErrorWritingData;
601 }
602
603 disable_input_thread = true;
604 const auto result = nfc_protocol->ReadMifare(data, out_data);
511 disable_input_thread = false; 605 disable_input_thread = false;
606
607 return result;
608}
609
610Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
611 std::scoped_lock lock{mutex};
612
613 if (!supported_features.nfc) {
614 return Common::Input::DriverResult::NotSupported;
615 }
616 if (!nfc_protocol->IsEnabled()) {
617 return Common::Input::DriverResult::Disabled;
618 }
619 if (!amiibo_detected) {
620 return Common::Input::DriverResult::ErrorWritingData;
621 }
622
623 disable_input_thread = true;
624 const auto result = nfc_protocol->WriteMifare(data);
625 disable_input_thread = false;
626
512 return result; 627 return result;
513} 628}
514 629
@@ -561,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) {
561 joycon_poller->SetCallbacks(callbacks); 676 joycon_poller->SetCallbacks(callbacks);
562} 677}
563 678
564DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, 679Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
565 ControllerType& controller_type) { 680 ControllerType& controller_type) {
566 static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{ 681 static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{
567 std::pair<u32, ControllerType>{0x2006, ControllerType::Left}, 682 std::pair<u32, ControllerType>{0x2006, ControllerType::Left},
568 {0x2007, ControllerType::Right}, 683 {0x2007, ControllerType::Right},
@@ -572,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
572 687
573 controller_type = ControllerType::None; 688 controller_type = ControllerType::None;
574 if (device_info->vendor_id != nintendo_vendor_id) { 689 if (device_info->vendor_id != nintendo_vendor_id) {
575 return DriverResult::UnsupportedControllerType; 690 return Common::Input::DriverResult::UnsupportedControllerType;
576 } 691 }
577 692
578 for (const auto& [product_id, type] : supported_devices) { 693 for (const auto& [product_id, type] : supported_devices) {
579 if (device_info->product_id == static_cast<u16>(product_id)) { 694 if (device_info->product_id == static_cast<u16>(product_id)) {
580 controller_type = type; 695 controller_type = type;
581 return Joycon::DriverResult::Success; 696 return Common::Input::DriverResult::Success;
582 } 697 }
583 } 698 }
584 return Joycon::DriverResult::UnsupportedControllerType; 699 return Common::Input::DriverResult::UnsupportedControllerType;
585} 700}
586 701
587DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, 702Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
588 SerialNumber& serial_number) { 703 SerialNumber& serial_number) {
589 if (device_info->serial_number == nullptr) { 704 if (device_info->serial_number == nullptr) {
590 return DriverResult::Unknown; 705 return Common::Input::DriverResult::Unknown;
591 } 706 }
592 std::memcpy(&serial_number, device_info->serial_number, 15); 707 std::memcpy(&serial_number, device_info->serial_number, 15);
593 return Joycon::DriverResult::Success; 708 return Common::Input::DriverResult::Success;
594} 709}
595 710
596} // namespace InputCommon::Joycon 711} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h
index e9b2fccbb..335e12cc3 100644
--- a/src/input_common/helpers/joycon_driver.h
+++ b/src/input_common/helpers/joycon_driver.h
@@ -11,6 +11,10 @@
11 11
12#include "input_common/helpers/joycon_protocol/joycon_types.h" 12#include "input_common/helpers/joycon_protocol/joycon_types.h"
13 13
14namespace Common::Input {
15enum class DriverResult;
16}
17
14namespace InputCommon::Joycon { 18namespace InputCommon::Joycon {
15class CalibrationProtocol; 19class CalibrationProtocol;
16class GenericProtocol; 20class GenericProtocol;
@@ -26,8 +30,8 @@ public:
26 30
27 ~JoyconDriver(); 31 ~JoyconDriver();
28 32
29 DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info); 33 Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
30 DriverResult InitializeDevice(); 34 Common::Input::DriverResult InitializeDevice();
31 void Stop(); 35 void Stop();
32 36
33 bool IsConnected() const; 37 bool IsConnected() const;
@@ -41,25 +45,31 @@ public:
41 SerialNumber GetSerialNumber() const; 45 SerialNumber GetSerialNumber() const;
42 SerialNumber GetHandleSerialNumber() const; 46 SerialNumber GetHandleSerialNumber() const;
43 47
44 DriverResult SetVibration(const VibrationValue& vibration); 48 Common::Input::DriverResult SetVibration(const VibrationValue& vibration);
45 DriverResult SetLedConfig(u8 led_pattern); 49 Common::Input::DriverResult SetLedConfig(u8 led_pattern);
46 DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); 50 Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
47 DriverResult SetPassiveMode(); 51 Common::Input::DriverResult SetPassiveMode();
48 DriverResult SetActiveMode(); 52 Common::Input::DriverResult SetActiveMode();
49 DriverResult SetIrMode(); 53 Common::Input::DriverResult SetIrMode();
50 DriverResult SetNfcMode(); 54 Common::Input::DriverResult SetNfcMode();
51 DriverResult SetRingConMode(); 55 Common::Input::DriverResult SetRingConMode();
52 DriverResult WriteNfcData(std::span<const u8> data); 56 Common::Input::DriverResult StartNfcPolling();
57 Common::Input::DriverResult StopNfcPolling();
58 Common::Input::DriverResult ReadAmiiboData(std::vector<u8>& out_data);
59 Common::Input::DriverResult WriteNfcData(std::span<const u8> data);
60 Common::Input::DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
61 std::span<MifareReadData> out_data);
62 Common::Input::DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
53 63
54 void SetCallbacks(const JoyconCallbacks& callbacks); 64 void SetCallbacks(const JoyconCallbacks& callbacks);
55 65
56 // Returns device type from hidapi handle 66 // Returns device type from hidapi handle
57 static DriverResult GetDeviceType(SDL_hid_device_info* device_info, 67 static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info,
58 ControllerType& controller_type); 68 ControllerType& controller_type);
59 69
60 // Returns serial number from hidapi handle 70 // Returns serial number from hidapi handle
61 static DriverResult GetSerialNumber(SDL_hid_device_info* device_info, 71 static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
62 SerialNumber& serial_number); 72 SerialNumber& serial_number);
63 73
64private: 74private:
65 struct SupportedFeatures { 75 struct SupportedFeatures {
@@ -78,7 +88,7 @@ private:
78 void OnNewData(std::span<u8> buffer); 88 void OnNewData(std::span<u8> buffer);
79 89
80 /// Updates device configuration to enable or disable features 90 /// Updates device configuration to enable or disable features
81 DriverResult SetPollingMode(); 91 Common::Input::DriverResult SetPollingMode();
82 92
83 /// Returns true if input thread is valid and doesn't need to be stopped 93 /// Returns true if input thread is valid and doesn't need to be stopped
84 bool IsInputThreadValid() const; 94 bool IsInputThreadValid() const;
@@ -114,6 +124,7 @@ private:
114 // Hardware configuration 124 // Hardware configuration
115 u8 leds{}; 125 u8 leds{};
116 ReportMode mode{}; 126 ReportMode mode{};
127 bool input_only_device{};
117 bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time 128 bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time
118 bool hidbus_enabled{}; // External device support 129 bool hidbus_enabled{}; // External device support
119 bool irs_enabled{}; // Infrared camera input 130 bool irs_enabled{}; // Infrared camera input
diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp
index d8f040f75..1300ecaf5 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.cpp
+++ b/src/input_common/helpers/joycon_protocol/calibration.cpp
@@ -3,6 +3,7 @@
3 3
4#include <cstring> 4#include <cstring>
5 5
6#include "common/input.h"
6#include "input_common/helpers/joycon_protocol/calibration.h" 7#include "input_common/helpers/joycon_protocol/calibration.h"
7#include "input_common/helpers/joycon_protocol/joycon_types.h" 8#include "input_common/helpers/joycon_protocol/joycon_types.h"
8 9
@@ -11,28 +12,29 @@ namespace InputCommon::Joycon {
11CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) 12CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
12 : JoyconCommonProtocol(std::move(handle)) {} 13 : JoyconCommonProtocol(std::move(handle)) {}
13 14
14DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { 15Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(
16 JoyStickCalibration& calibration) {
15 ScopedSetBlocking sb(this); 17 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 18 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 JoystickLeftSpiCalibration spi_calibration{}; 19 JoystickLeftSpiCalibration spi_calibration{};
18 bool has_user_calibration = false; 20 bool has_user_calibration = false;
19 calibration = {}; 21 calibration = {};
20 22
21 if (result == DriverResult::Success) { 23 if (result == Common::Input::DriverResult::Success) {
22 result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration); 24 result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
23 } 25 }
24 26
25 // Read User defined calibration 27 // Read User defined calibration
26 if (result == DriverResult::Success && has_user_calibration) { 28 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
27 result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration); 29 result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
28 } 30 }
29 31
30 // Read Factory calibration 32 // Read Factory calibration
31 if (result == DriverResult::Success && !has_user_calibration) { 33 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
32 result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration); 34 result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
33 } 35 }
34 36
35 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
36 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); 38 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
37 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); 39 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
38 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); 40 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
47 return result; 49 return result;
48} 50}
49 51
50DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { 52Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration(
53 JoyStickCalibration& calibration) {
51 ScopedSetBlocking sb(this); 54 ScopedSetBlocking sb(this);
52 DriverResult result{DriverResult::Success}; 55 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
53 JoystickRightSpiCalibration spi_calibration{}; 56 JoystickRightSpiCalibration spi_calibration{};
54 bool has_user_calibration = false; 57 bool has_user_calibration = false;
55 calibration = {}; 58 calibration = {};
56 59
57 if (result == DriverResult::Success) { 60 if (result == Common::Input::DriverResult::Success) {
58 result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration); 61 result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
59 } 62 }
60 63
61 // Read User defined calibration 64 // Read User defined calibration
62 if (result == DriverResult::Success && has_user_calibration) { 65 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
63 result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration); 66 result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
64 } 67 }
65 68
66 // Read Factory calibration 69 // Read Factory calibration
67 if (result == DriverResult::Success && !has_user_calibration) { 70 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
68 result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration); 71 result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
69 } 72 }
70 73
71 if (result == DriverResult::Success) { 74 if (result == Common::Input::DriverResult::Success) {
72 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); 75 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
73 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); 76 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
74 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); 77 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
83 return result; 86 return result;
84} 87}
85 88
86DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { 89Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
87 ScopedSetBlocking sb(this); 90 ScopedSetBlocking sb(this);
88 DriverResult result{DriverResult::Success}; 91 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
89 ImuSpiCalibration spi_calibration{}; 92 ImuSpiCalibration spi_calibration{};
90 bool has_user_calibration = false; 93 bool has_user_calibration = false;
91 calibration = {}; 94 calibration = {};
92 95
93 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
94 result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration); 97 result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
95 } 98 }
96 99
97 // Read User defined calibration 100 // Read User defined calibration
98 if (result == DriverResult::Success && has_user_calibration) { 101 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
99 result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration); 102 result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
100 } 103 }
101 104
102 // Read Factory calibration 105 // Read Factory calibration
103 if (result == DriverResult::Success && !has_user_calibration) { 106 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
104 result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration); 107 result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
105 } 108 }
106 109
107 if (result == DriverResult::Success) { 110 if (result == Common::Input::DriverResult::Success) {
108 calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0]; 111 calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
109 calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1]; 112 calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
110 calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2]; 113 calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
@@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
127 return result; 130 return result;
128} 131}
129 132
130DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, 133Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
131 s16 current_value) { 134 s16 current_value) {
132 constexpr s16 DefaultRingRange{800}; 135 constexpr s16 DefaultRingRange{800};
133 136
134 // TODO: Get default calibration form ring itself 137 // TODO: Get default calibration form ring itself
@@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
144 .max_value = ring_data_max, 147 .max_value = ring_data_max,
145 .min_value = ring_data_min, 148 .min_value = ring_data_min,
146 }; 149 };
147 return DriverResult::Success; 150 return Common::Input::DriverResult::Success;
148} 151}
149 152
150DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, 153Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
151 bool& has_user_calibration) { 154 bool& has_user_calibration) {
152 MagicSpiCalibration spi_magic{}; 155 MagicSpiCalibration spi_magic{};
153 const DriverResult result{ReadSPI(address, spi_magic)}; 156 const Common::Input::DriverResult result{ReadSPI(address, spi_magic)};
154 has_user_calibration = false; 157 has_user_calibration = false;
155 if (result == DriverResult::Success) { 158 if (result == Common::Input::DriverResult::Success) {
156 has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 && 159 has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
157 spi_magic.second == CalibrationMagic::USR_MAGIC_1; 160 spi_magic.second == CalibrationMagic::USR_MAGIC_1;
158 } 161 }
diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h
index c6fd0f729..82d94b366 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.h
+++ b/src/input_common/helpers/joycon_protocol/calibration.h
@@ -12,8 +12,11 @@
12 12
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14 14
15namespace InputCommon::Joycon { 15namespace Common::Input {
16enum class DriverResult; 16enum class DriverResult;
17}
18
19namespace InputCommon::Joycon {
17struct JoyStickCalibration; 20struct JoyStickCalibration;
18struct IMUCalibration; 21struct IMUCalibration;
19struct JoyconHandle; 22struct JoyconHandle;
@@ -31,30 +34,30 @@ public:
31 * @param is_factory_calibration if true factory values will be returned 34 * @param is_factory_calibration if true factory values will be returned
32 * @returns JoyStickCalibration of the left joystick 35 * @returns JoyStickCalibration of the left joystick
33 */ 36 */
34 DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration); 37 Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
35 38
36 /** 39 /**
37 * Sends a request to obtain the right stick calibration from memory 40 * Sends a request to obtain the right stick calibration from memory
38 * @param is_factory_calibration if true factory values will be returned 41 * @param is_factory_calibration if true factory values will be returned
39 * @returns JoyStickCalibration of the right joystick 42 * @returns JoyStickCalibration of the right joystick
40 */ 43 */
41 DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration); 44 Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
42 45
43 /** 46 /**
44 * Sends a request to obtain the motion calibration from memory 47 * Sends a request to obtain the motion calibration from memory
45 * @returns ImuCalibration of the motion sensor 48 * @returns ImuCalibration of the motion sensor
46 */ 49 */
47 DriverResult GetImuCalibration(MotionCalibration& calibration); 50 Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration);
48 51
49 /** 52 /**
50 * Calculates on run time the proper calibration of the ring controller 53 * Calculates on run time the proper calibration of the ring controller
51 * @returns RingCalibration of the ring sensor 54 * @returns RingCalibration of the ring sensor
52 */ 55 */
53 DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); 56 Common::Input::DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
54 57
55private: 58private:
56 /// Returns true if the specified address corresponds to the magic value of user calibration 59 /// Returns true if the specified address corresponds to the magic value of user calibration
57 DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); 60 Common::Input::DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
58 61
59 /// Converts a raw calibration block to an u16 value containing the x axis value 62 /// Converts a raw calibration block to an u16 value containing the x axis value
60 u16 GetXAxisCalibrationValue(std::span<u8> block) const; 63 u16 GetXAxisCalibrationValue(std::span<u8> block) const;
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 51669261a..a6eecf980 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/common_protocol.h" 6#include "input_common/helpers/joycon_protocol/common_protocol.h"
6 7
@@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() {
21 SDL_hid_set_nonblocking(hidapi_handle->handle, 1); 22 SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
22} 23}
23 24
24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { 25Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
25 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); 26 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
26 27
27 if (result == DriverResult::Success) { 28 if (result == Common::Input::DriverResult::Success) {
28 // Fallback to 3rd party pro controllers 29 // Fallback to 3rd party pro controllers
29 if (controller_type == ControllerType::None) { 30 if (controller_type == ControllerType::None) {
30 controller_type = ControllerType::Pro; 31 controller_type = ControllerType::Pro;
@@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
34 return result; 35 return result;
35} 36}
36 37
37DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { 38Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(
39 SDL_hid_device_info* device_info) {
38 ControllerType controller_type{ControllerType::None}; 40 ControllerType controller_type{ControllerType::None};
39 const auto result = GetDeviceType(controller_type); 41 const auto result = GetDeviceType(controller_type);
40 42
41 if (result != DriverResult::Success || controller_type == ControllerType::None) { 43 if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) {
42 return DriverResult::UnsupportedControllerType; 44 return Common::Input::DriverResult::UnsupportedControllerType;
43 } 45 }
44 46
45 hidapi_handle->handle = 47 hidapi_handle->handle =
@@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device
48 if (!hidapi_handle->handle) { 50 if (!hidapi_handle->handle) {
49 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", 51 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
50 device_info->vendor_id, device_info->product_id); 52 device_info->vendor_id, device_info->product_id);
51 return DriverResult::HandleInUse; 53 return Common::Input::DriverResult::HandleInUse;
52 } 54 }
53 55
54 SetNonBlocking(); 56 SetNonBlocking();
55 return DriverResult::Success; 57 return Common::Input::DriverResult::Success;
56} 58}
57 59
58DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { 60Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
59 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)}; 61 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)};
60 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); 62 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
61} 63}
62 64
63DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { 65Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
64 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); 66 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
65 67
66 if (result == -1) { 68 if (result == -1) {
67 return DriverResult::ErrorWritingData; 69 return Common::Input::DriverResult::ErrorWritingData;
68 } 70 }
69 71
70 return DriverResult::Success; 72 return Common::Input::DriverResult::Success;
71} 73}
72 74
73DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, 75Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(
74 SubCommandResponse& output) { 76 SubCommand sc, SubCommandResponse& output) {
75 constexpr int timeout_mili = 66; 77 constexpr int timeout_mili = 66;
76 constexpr int MaxTries = 15; 78 constexpr int MaxTries = 10;
77 int tries = 0; 79 int tries = 0;
78 80
79 do { 81 do {
@@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
84 LOG_ERROR(Input, "No response from joycon"); 86 LOG_ERROR(Input, "No response from joycon");
85 } 87 }
86 if (tries++ > MaxTries) { 88 if (tries++ > MaxTries) {
87 return DriverResult::Timeout; 89 return Common::Input::DriverResult::Timeout;
88 } 90 }
89 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && 91 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
90 output.sub_command != sc); 92 output.sub_command != sc);
91 93
92 return DriverResult::Success; 94 return Common::Input::DriverResult::Success;
93} 95}
94 96
95DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, 97Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
96 SubCommandResponse& output) { 98 std::span<const u8> buffer,
99 SubCommandResponse& output) {
97 SubCommandPacket packet{ 100 SubCommandPacket packet{
98 .output_report = OutputReport::RUMBLE_AND_SUBCMD, 101 .output_report = OutputReport::RUMBLE_AND_SUBCMD,
99 .packet_counter = GetCounter(), 102 .packet_counter = GetCounter(),
@@ -102,28 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
102 }; 105 };
103 106
104 if (buffer.size() > packet.command_data.size()) { 107 if (buffer.size() > packet.command_data.size()) {
105 return DriverResult::InvalidParameters; 108 return Common::Input::DriverResult::InvalidParameters;
106 } 109 }
107 110
108 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 111 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
109 112
110 auto result = SendData(packet); 113 auto result = SendData(packet);
111 114
112 if (result != DriverResult::Success) { 115 if (result != Common::Input::DriverResult::Success) {
113 return result; 116 return result;
114 } 117 }
115 118
116 result = GetSubCommandResponse(sc, output); 119 return GetSubCommandResponse(sc, output);
117
118 return DriverResult::Success;
119} 120}
120 121
121DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { 122Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
123 std::span<const u8> buffer) {
122 SubCommandResponse output{}; 124 SubCommandResponse output{};
123 return SendSubCommand(sc, buffer, output); 125 return SendSubCommand(sc, buffer, output);
124} 126}
125 127
126DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { 128Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc,
129 std::span<const u8> buffer) {
127 SubCommandPacket packet{ 130 SubCommandPacket packet{
128 .output_report = OutputReport::MCU_DATA, 131 .output_report = OutputReport::MCU_DATA,
129 .packet_counter = GetCounter(), 132 .packet_counter = GetCounter(),
@@ -132,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
132 }; 135 };
133 136
134 if (buffer.size() > packet.command_data.size()) { 137 if (buffer.size() > packet.command_data.size()) {
135 return DriverResult::InvalidParameters; 138 return Common::Input::DriverResult::InvalidParameters;
136 } 139 }
137 140
138 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 141 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
@@ -140,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
140 return SendData(packet); 143 return SendData(packet);
141} 144}
142 145
143DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { 146Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
144 VibrationPacket packet{ 147 VibrationPacket packet{
145 .output_report = OutputReport::RUMBLE_ONLY, 148 .output_report = OutputReport::RUMBLE_ONLY,
146 .packet_counter = GetCounter(), 149 .packet_counter = GetCounter(),
@@ -148,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
148 }; 151 };
149 152
150 if (buffer.size() > packet.vibration_data.size()) { 153 if (buffer.size() > packet.vibration_data.size()) {
151 return DriverResult::InvalidParameters; 154 return Common::Input::DriverResult::InvalidParameters;
152 } 155 }
153 156
154 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); 157 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
@@ -156,9 +159,10 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
156 return SendData(packet); 159 return SendData(packet);
157} 160}
158 161
159DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { 162Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr,
163 std::span<u8> output) {
160 constexpr std::size_t HeaderSize = 5; 164 constexpr std::size_t HeaderSize = 5;
161 constexpr std::size_t MaxTries = 10; 165 constexpr std::size_t MaxTries = 5;
162 std::size_t tries = 0; 166 std::size_t tries = 0;
163 SubCommandResponse response{}; 167 SubCommandResponse response{};
164 std::array<u8, sizeof(ReadSpiPacket)> buffer{}; 168 std::array<u8, sizeof(ReadSpiPacket)> buffer{};
@@ -170,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
170 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); 174 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
171 do { 175 do {
172 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); 176 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
173 if (result != DriverResult::Success) { 177 if (result != Common::Input::DriverResult::Success) {
174 return result; 178 return result;
175 } 179 }
176 180
177 if (tries++ > MaxTries) { 181 if (tries++ > MaxTries) {
178 return DriverResult::Timeout; 182 return Common::Input::DriverResult::Timeout;
179 } 183 }
180 } while (response.spi_address != addr); 184 } while (response.spi_address != addr);
181 185
182 if (response.command_data.size() < packet_data.size + HeaderSize) { 186 if (response.command_data.size() < packet_data.size + HeaderSize) {
183 return DriverResult::WrongReply; 187 return Common::Input::DriverResult::WrongReply;
184 } 188 }
185 189
186 // Remove header from output 190 // Remove header from output
187 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); 191 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
188 return DriverResult::Success; 192 return Common::Input::DriverResult::Success;
189} 193}
190 194
191DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { 195Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
192 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)}; 196 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)};
193 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); 197 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
194 198
195 if (result != DriverResult::Success) { 199 if (result != Common::Input::DriverResult::Success) {
196 LOG_ERROR(Input, "Failed with error {}", result); 200 LOG_ERROR(Input, "Failed with error {}", result);
197 } 201 }
198 202
199 return result; 203 return result;
200} 204}
201 205
202DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { 206Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
203 LOG_DEBUG(Input, "ConfigureMCU"); 207 LOG_DEBUG(Input, "ConfigureMCU");
204 std::array<u8, sizeof(MCUConfig)> config_buffer; 208 std::array<u8, sizeof(MCUConfig)> config_buffer;
205 memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); 209 memcpy(config_buffer.data(), &config, sizeof(MCUConfig));
@@ -207,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
207 211
208 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); 212 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
209 213
210 if (result != DriverResult::Success) { 214 if (result != Common::Input::DriverResult::Success) {
211 LOG_ERROR(Input, "Failed with error {}", result); 215 LOG_ERROR(Input, "Failed with error {}", result);
212 } 216 }
213 217
214 return result; 218 return result;
215} 219}
216 220
217DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, 221Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
218 MCUCommandResponse& output) { 222 MCUCommandResponse& output) {
219 constexpr int TimeoutMili = 200; 223 constexpr int TimeoutMili = 200;
220 constexpr int MaxTries = 9; 224 constexpr int MaxTries = 9;
221 int tries = 0; 225 int tries = 0;
@@ -228,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
228 LOG_ERROR(Input, "No response from joycon attempt {}", tries); 232 LOG_ERROR(Input, "No response from joycon attempt {}", tries);
229 } 233 }
230 if (tries++ > MaxTries) { 234 if (tries++ > MaxTries) {
231 return DriverResult::Timeout; 235 return Common::Input::DriverResult::Timeout;
232 } 236 }
233 } while (output.input_report.report_mode != report_mode || 237 } while (output.input_report.report_mode != report_mode ||
234 output.mcu_report == MCUReport::EmptyAwaitingCmd); 238 output.mcu_report == MCUReport::EmptyAwaitingCmd);
235 239
236 return DriverResult::Success; 240 return Common::Input::DriverResult::Success;
237} 241}
238 242
239DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc, 243Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode,
240 std::span<const u8> buffer, 244 MCUSubCommand sc,
241 MCUCommandResponse& output) { 245 std::span<const u8> buffer,
246 MCUCommandResponse& output) {
242 SubCommandPacket packet{ 247 SubCommandPacket packet{
243 .output_report = OutputReport::MCU_DATA, 248 .output_report = OutputReport::MCU_DATA,
244 .packet_counter = GetCounter(), 249 .packet_counter = GetCounter(),
@@ -247,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom
247 }; 252 };
248 253
249 if (buffer.size() > packet.command_data.size()) { 254 if (buffer.size() > packet.command_data.size()) {
250 return DriverResult::InvalidParameters; 255 return Common::Input::DriverResult::InvalidParameters;
251 } 256 }
252 257
253 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 258 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
254 259
255 auto result = SendData(packet); 260 auto result = SendData(packet);
256 261
257 if (result != DriverResult::Success) { 262 if (result != Common::Input::DriverResult::Success) {
258 return result; 263 return result;
259 } 264 }
260 265
261 result = GetMCUDataResponse(report_mode, output); 266 result = GetMCUDataResponse(report_mode, output);
262 267
263 return DriverResult::Success; 268 return Common::Input::DriverResult::Success;
264} 269}
265 270
266DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { 271Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode,
272 MCUMode mode) {
267 MCUCommandResponse output{}; 273 MCUCommandResponse output{};
268 constexpr std::size_t MaxTries{16}; 274 constexpr std::size_t MaxTries{16};
269 std::size_t tries{}; 275 std::size_t tries{};
@@ -271,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
271 do { 277 do {
272 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output); 278 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
273 279
274 if (result != DriverResult::Success) { 280 if (result != Common::Input::DriverResult::Success) {
275 return result; 281 return result;
276 } 282 }
277 283
278 if (tries++ > MaxTries) { 284 if (tries++ > MaxTries) {
279 return DriverResult::WrongReply; 285 return Common::Input::DriverResult::WrongReply;
280 } 286 }
281 } while (output.mcu_report != MCUReport::StateReport || 287 } while (output.mcu_report != MCUReport::StateReport ||
282 output.mcu_data[6] != static_cast<u8>(mode)); 288 output.mcu_data[6] != static_cast<u8>(mode));
283 289
284 return DriverResult::Success; 290 return Common::Input::DriverResult::Success;
285} 291}
286 292
287// crc-8-ccitt / polynomial 0x07 look up table 293// crc-8-ccitt / polynomial 0x07 look up table
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 411ec018a..dd667ca2b 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -38,30 +38,30 @@ public:
38 * Sends a request to obtain the joycon type from device 38 * Sends a request to obtain the joycon type from device
39 * @returns controller type of the joycon 39 * @returns controller type of the joycon
40 */ 40 */
41 DriverResult GetDeviceType(ControllerType& controller_type); 41 Common::Input::DriverResult GetDeviceType(ControllerType& controller_type);
42 42
43 /** 43 /**
44 * Verifies and sets the joycon_handle if device is valid 44 * Verifies and sets the joycon_handle if device is valid
45 * @param device info from the driver 45 * @param device info from the driver
46 * @returns success if the device is valid 46 * @returns success if the device is valid
47 */ 47 */
48 DriverResult CheckDeviceAccess(SDL_hid_device_info* device); 48 Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
49 49
50 /** 50 /**
51 * Sends a request to set the polling mode of the joycon 51 * Sends a request to set the polling mode of the joycon
52 * @param report_mode polling mode to be set 52 * @param report_mode polling mode to be set
53 */ 53 */
54 DriverResult SetReportMode(Joycon::ReportMode report_mode); 54 Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode);
55 55
56 /** 56 /**
57 * Sends data to the joycon device 57 * Sends data to the joycon device
58 * @param buffer data to be send 58 * @param buffer data to be send
59 */ 59 */
60 DriverResult SendRawData(std::span<const u8> buffer); 60 Common::Input::DriverResult SendRawData(std::span<const u8> buffer);
61 61
62 template <typename Output> 62 template <typename Output>
63 requires std::is_trivially_copyable_v<Output> 63 requires std::is_trivially_copyable_v<Output>
64 DriverResult SendData(const Output& output) { 64 Common::Input::DriverResult SendData(const Output& output) {
65 std::array<u8, sizeof(Output)> buffer; 65 std::array<u8, sizeof(Output)> buffer;
66 std::memcpy(buffer.data(), &output, sizeof(Output)); 66 std::memcpy(buffer.data(), &output, sizeof(Output));
67 return SendRawData(buffer); 67 return SendRawData(buffer);
@@ -72,7 +72,8 @@ public:
72 * @param sub_command type of data to be returned 72 * @param sub_command type of data to be returned
73 * @returns a buffer containing the response 73 * @returns a buffer containing the response
74 */ 74 */
75 DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output); 75 Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command,
76 SubCommandResponse& output);
76 77
77 /** 78 /**
78 * Sends a sub command to the device and waits for it's reply 79 * Sends a sub command to the device and waits for it's reply
@@ -80,35 +81,35 @@ public:
80 * @param buffer data to be send 81 * @param buffer data to be send
81 * @returns output buffer containing the response 82 * @returns output buffer containing the response
82 */ 83 */
83 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, 84 Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
84 SubCommandResponse& output); 85 SubCommandResponse& output);
85 86
86 /** 87 /**
87 * Sends a sub command to the device and waits for it's reply and ignores the output 88 * Sends a sub command to the device and waits for it's reply and ignores the output
88 * @param sc sub command to be send 89 * @param sc sub command to be send
89 * @param buffer data to be send 90 * @param buffer data to be send
90 */ 91 */
91 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer); 92 Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
92 93
93 /** 94 /**
94 * Sends a mcu command to the device 95 * Sends a mcu command to the device
95 * @param sc sub command to be send 96 * @param sc sub command to be send
96 * @param buffer data to be send 97 * @param buffer data to be send
97 */ 98 */
98 DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer); 99 Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
99 100
100 /** 101 /**
101 * Sends vibration data to the joycon 102 * Sends vibration data to the joycon
102 * @param buffer data to be send 103 * @param buffer data to be send
103 */ 104 */
104 DriverResult SendVibrationReport(std::span<const u8> buffer); 105 Common::Input::DriverResult SendVibrationReport(std::span<const u8> buffer);
105 106
106 /** 107 /**
107 * Reads the SPI memory stored on the joycon 108 * Reads the SPI memory stored on the joycon
108 * @param Initial address location 109 * @param Initial address location
109 * @returns output buffer containing the response 110 * @returns output buffer containing the response
110 */ 111 */
111 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); 112 Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
112 113
113 /** 114 /**
114 * Reads the SPI memory stored on the joycon 115 * Reads the SPI memory stored on the joycon
@@ -117,37 +118,38 @@ public:
117 */ 118 */
118 template <typename Output> 119 template <typename Output>
119 requires std::is_trivially_copyable_v<Output> 120 requires std::is_trivially_copyable_v<Output>
120 DriverResult ReadSPI(SpiAddress addr, Output& output) { 121 Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) {
121 std::array<u8, sizeof(Output)> buffer; 122 std::array<u8, sizeof(Output)> buffer;
122 output = {}; 123 output = {};
123 124
124 const auto result = ReadRawSPI(addr, buffer); 125 const auto result = ReadRawSPI(addr, buffer);
125 if (result != DriverResult::Success) { 126 if (result != Common::Input::DriverResult::Success) {
126 return result; 127 return result;
127 } 128 }
128 129
129 std::memcpy(&output, buffer.data(), sizeof(Output)); 130 std::memcpy(&output, buffer.data(), sizeof(Output));
130 return DriverResult::Success; 131 return Common::Input::DriverResult::Success;
131 } 132 }
132 133
133 /** 134 /**
134 * Enables MCU chip on the joycon 135 * Enables MCU chip on the joycon
135 * @param enable if true the chip will be enabled 136 * @param enable if true the chip will be enabled
136 */ 137 */
137 DriverResult EnableMCU(bool enable); 138 Common::Input::DriverResult EnableMCU(bool enable);
138 139
139 /** 140 /**
140 * Configures the MCU to the corresponding mode 141 * Configures the MCU to the corresponding mode
141 * @param MCUConfig configuration 142 * @param MCUConfig configuration
142 */ 143 */
143 DriverResult ConfigureMCU(const MCUConfig& config); 144 Common::Input::DriverResult ConfigureMCU(const MCUConfig& config);
144 145
145 /** 146 /**
146 * Waits until there's MCU data available. On timeout returns error 147 * Waits until there's MCU data available. On timeout returns error
147 * @param report mode of the expected reply 148 * @param report mode of the expected reply
148 * @returns a buffer containing the response 149 * @returns a buffer containing the response
149 */ 150 */
150 DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output); 151 Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_,
152 MCUCommandResponse& output);
151 153
152 /** 154 /**
153 * Sends data to the MCU chip and waits for it's reply 155 * Sends data to the MCU chip and waits for it's reply
@@ -156,15 +158,15 @@ public:
156 * @param buffer data to be send 158 * @param buffer data to be send
157 * @returns output buffer containing the response 159 * @returns output buffer containing the response
158 */ 160 */
159 DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer, 161 Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc,
160 MCUCommandResponse& output); 162 std::span<const u8> buffer, MCUCommandResponse& output);
161 163
162 /** 164 /**
163 * Wait's until the MCU chip is on the specified mode 165 * Wait's until the MCU chip is on the specified mode
164 * @param report mode of the expected reply 166 * @param report mode of the expected reply
165 * @param MCUMode configuration 167 * @param MCUMode configuration
166 */ 168 */
167 DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode); 169 Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
168 170
169 /** 171 /**
170 * Calculates the checksum from the MCU data 172 * Calculates the checksum from the MCU data
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
index 548a4b9e3..e9a056448 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/generic_functions.h" 6#include "input_common/helpers/joycon_protocol/generic_functions.h"
6 7
@@ -9,73 +10,74 @@ namespace InputCommon::Joycon {
9GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) 10GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle)
10 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
11 12
12DriverResult GenericProtocol::EnablePassiveMode() { 13Common::Input::DriverResult GenericProtocol::EnablePassiveMode() {
13 ScopedSetBlocking sb(this); 14 ScopedSetBlocking sb(this);
14 return SetReportMode(ReportMode::SIMPLE_HID_MODE); 15 return SetReportMode(ReportMode::SIMPLE_HID_MODE);
15} 16}
16 17
17DriverResult GenericProtocol::EnableActiveMode() { 18Common::Input::DriverResult GenericProtocol::EnableActiveMode() {
18 ScopedSetBlocking sb(this); 19 ScopedSetBlocking sb(this);
19 return SetReportMode(ReportMode::STANDARD_FULL_60HZ); 20 return SetReportMode(ReportMode::STANDARD_FULL_60HZ);
20} 21}
21 22
22DriverResult GenericProtocol::SetLowPowerMode(bool enable) { 23Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
23 ScopedSetBlocking sb(this); 24 ScopedSetBlocking sb(this);
24 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; 25 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
25 return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer); 26 return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer);
26} 27}
27 28
28DriverResult GenericProtocol::TriggersElapsed() { 29Common::Input::DriverResult GenericProtocol::TriggersElapsed() {
29 ScopedSetBlocking sb(this); 30 ScopedSetBlocking sb(this);
30 return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {}); 31 return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {});
31} 32}
32 33
33DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { 34Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
34 ScopedSetBlocking sb(this); 35 ScopedSetBlocking sb(this);
35 SubCommandResponse output{}; 36 SubCommandResponse output{};
36 37
37 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); 38 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
38 39
39 device_info = {}; 40 device_info = {};
40 if (result == DriverResult::Success) { 41 if (result == Common::Input::DriverResult::Success) {
41 device_info = output.device_info; 42 device_info = output.device_info;
42 } 43 }
43 44
44 return result; 45 return result;
45} 46}
46 47
47DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { 48Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
48 return GetDeviceType(controller_type); 49 return GetDeviceType(controller_type);
49} 50}
50 51
51DriverResult GenericProtocol::EnableImu(bool enable) { 52Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) {
52 ScopedSetBlocking sb(this); 53 ScopedSetBlocking sb(this);
53 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; 54 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
54 return SendSubCommand(SubCommand::ENABLE_IMU, buffer); 55 return SendSubCommand(SubCommand::ENABLE_IMU, buffer);
55} 56}
56 57
57DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, 58Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen,
58 AccelerometerSensitivity asen, 59 GyroPerformance gfrec,
59 AccelerometerPerformance afrec) { 60 AccelerometerSensitivity asen,
61 AccelerometerPerformance afrec) {
60 ScopedSetBlocking sb(this); 62 ScopedSetBlocking sb(this);
61 const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), 63 const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
62 static_cast<u8>(gfrec), static_cast<u8>(afrec)}; 64 static_cast<u8>(gfrec), static_cast<u8>(afrec)};
63 return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer); 65 return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer);
64} 66}
65 67
66DriverResult GenericProtocol::GetBattery(u32& battery_level) { 68Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) {
67 // This function is meant to request the high resolution battery status 69 // This function is meant to request the high resolution battery status
68 battery_level = 0; 70 battery_level = 0;
69 return DriverResult::NotSupported; 71 return Common::Input::DriverResult::NotSupported;
70} 72}
71 73
72DriverResult GenericProtocol::GetColor(Color& color) { 74Common::Input::DriverResult GenericProtocol::GetColor(Color& color) {
73 ScopedSetBlocking sb(this); 75 ScopedSetBlocking sb(this);
74 std::array<u8, 12> buffer{}; 76 std::array<u8, 12> buffer{};
75 const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer); 77 const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
76 78
77 color = {}; 79 color = {};
78 if (result == DriverResult::Success) { 80 if (result == Common::Input::DriverResult::Success) {
79 color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); 81 color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]);
80 color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]); 82 color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]);
81 color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]); 83 color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]);
@@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) {
85 return result; 87 return result;
86} 88}
87 89
88DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { 90Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
89 ScopedSetBlocking sb(this); 91 ScopedSetBlocking sb(this);
90 std::array<u8, 16> buffer{}; 92 std::array<u8, 16> buffer{};
91 const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer); 93 const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
92 94
93 serial_number = {}; 95 serial_number = {};
94 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
95 memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber)); 97 memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber));
96 } 98 }
97 99
98 return result; 100 return result;
99} 101}
100 102
101DriverResult GenericProtocol::GetTemperature(u32& temperature) { 103Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) {
102 // Not all devices have temperature sensor 104 // Not all devices have temperature sensor
103 temperature = 25; 105 temperature = 25;
104 return DriverResult::NotSupported; 106 return Common::Input::DriverResult::NotSupported;
105} 107}
106 108
107DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { 109Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
108 DeviceInfo device_info{}; 110 DeviceInfo device_info{};
109 111
110 const auto result = GetDeviceInfo(device_info); 112 const auto result = GetDeviceInfo(device_info);
@@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
113 return result; 115 return result;
114} 116}
115 117
116DriverResult GenericProtocol::SetHomeLight() { 118Common::Input::DriverResult GenericProtocol::SetHomeLight() {
117 ScopedSetBlocking sb(this); 119 ScopedSetBlocking sb(this);
118 static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00}; 120 static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00};
119 return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer); 121 return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer);
120} 122}
121 123
122DriverResult GenericProtocol::SetLedBusy() { 124Common::Input::DriverResult GenericProtocol::SetLedBusy() {
123 return DriverResult::NotSupported; 125 return Common::Input::DriverResult::NotSupported;
124} 126}
125 127
126DriverResult GenericProtocol::SetLedPattern(u8 leds) { 128Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) {
127 ScopedSetBlocking sb(this); 129 ScopedSetBlocking sb(this);
128 const std::array<u8, 1> buffer{leds}; 130 const std::array<u8, 1> buffer{leds};
129 return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer); 131 return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer);
130} 132}
131 133
132DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { 134Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
133 return SetLedPattern(static_cast<u8>(leds << 4)); 135 return SetLedPattern(static_cast<u8>(leds << 4));
134} 136}
135 137
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.h b/src/input_common/helpers/joycon_protocol/generic_functions.h
index 424831e81..90fcd17f6 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.h
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.h
@@ -11,6 +11,10 @@
11#include "input_common/helpers/joycon_protocol/common_protocol.h" 11#include "input_common/helpers/joycon_protocol/common_protocol.h"
12#include "input_common/helpers/joycon_protocol/joycon_types.h" 12#include "input_common/helpers/joycon_protocol/joycon_types.h"
13 13
14namespace Common::Input {
15enum class DriverResult;
16}
17
14namespace InputCommon::Joycon { 18namespace InputCommon::Joycon {
15 19
16/// Joycon driver functions that easily implemented 20/// Joycon driver functions that easily implemented
@@ -20,34 +24,34 @@ public:
20 24
21 /// Enables passive mode. This mode only sends button data on change. Sticks will return digital 25 /// Enables passive mode. This mode only sends button data on change. Sticks will return digital
22 /// data instead of analog. Motion will be disabled 26 /// data instead of analog. Motion will be disabled
23 DriverResult EnablePassiveMode(); 27 Common::Input::DriverResult EnablePassiveMode();
24 28
25 /// Enables active mode. This mode will return the current status every 5-15ms 29 /// Enables active mode. This mode will return the current status every 5-15ms
26 DriverResult EnableActiveMode(); 30 Common::Input::DriverResult EnableActiveMode();
27 31
28 /// Enables or disables the low power mode 32 /// Enables or disables the low power mode
29 DriverResult SetLowPowerMode(bool enable); 33 Common::Input::DriverResult SetLowPowerMode(bool enable);
30 34
31 /// Unknown function used by the switch 35 /// Unknown function used by the switch
32 DriverResult TriggersElapsed(); 36 Common::Input::DriverResult TriggersElapsed();
33 37
34 /** 38 /**
35 * Sends a request to obtain the joycon firmware and mac from handle 39 * Sends a request to obtain the joycon firmware and mac from handle
36 * @returns controller device info 40 * @returns controller device info
37 */ 41 */
38 DriverResult GetDeviceInfo(DeviceInfo& controller_type); 42 Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type);
39 43
40 /** 44 /**
41 * Sends a request to obtain the joycon type from handle 45 * Sends a request to obtain the joycon type from handle
42 * @returns controller type of the joycon 46 * @returns controller type of the joycon
43 */ 47 */
44 DriverResult GetControllerType(ControllerType& controller_type); 48 Common::Input::DriverResult GetControllerType(ControllerType& controller_type);
45 49
46 /** 50 /**
47 * Enables motion input 51 * Enables motion input
48 * @param enable if true motion data will be enabled 52 * @param enable if true motion data will be enabled
49 */ 53 */
50 DriverResult EnableImu(bool enable); 54 Common::Input::DriverResult EnableImu(bool enable);
51 55
52 /** 56 /**
53 * Configures the motion sensor with the specified parameters 57 * Configures the motion sensor with the specified parameters
@@ -56,59 +60,60 @@ public:
56 * @param asen accelerometer sensitivity in G force 60 * @param asen accelerometer sensitivity in G force
57 * @param afrec accelerometer frequency in hertz 61 * @param afrec accelerometer frequency in hertz
58 */ 62 */
59 DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, 63 Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
60 AccelerometerSensitivity asen, AccelerometerPerformance afrec); 64 AccelerometerSensitivity asen,
65 AccelerometerPerformance afrec);
61 66
62 /** 67 /**
63 * Request battery level from the device 68 * Request battery level from the device
64 * @returns battery level 69 * @returns battery level
65 */ 70 */
66 DriverResult GetBattery(u32& battery_level); 71 Common::Input::DriverResult GetBattery(u32& battery_level);
67 72
68 /** 73 /**
69 * Request joycon colors from the device 74 * Request joycon colors from the device
70 * @returns colors of the body and buttons 75 * @returns colors of the body and buttons
71 */ 76 */
72 DriverResult GetColor(Color& color); 77 Common::Input::DriverResult GetColor(Color& color);
73 78
74 /** 79 /**
75 * Request joycon serial number from the device 80 * Request joycon serial number from the device
76 * @returns 16 byte serial number 81 * @returns 16 byte serial number
77 */ 82 */
78 DriverResult GetSerialNumber(SerialNumber& serial_number); 83 Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number);
79 84
80 /** 85 /**
81 * Request joycon serial number from the device 86 * Request joycon serial number from the device
82 * @returns 16 byte serial number 87 * @returns 16 byte serial number
83 */ 88 */
84 DriverResult GetTemperature(u32& temperature); 89 Common::Input::DriverResult GetTemperature(u32& temperature);
85 90
86 /** 91 /**
87 * Request joycon serial number from the device 92 * Request joycon serial number from the device
88 * @returns 16 byte serial number 93 * @returns 16 byte serial number
89 */ 94 */
90 DriverResult GetVersionNumber(FirmwareVersion& version); 95 Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version);
91 96
92 /** 97 /**
93 * Sets home led behaviour 98 * Sets home led behaviour
94 */ 99 */
95 DriverResult SetHomeLight(); 100 Common::Input::DriverResult SetHomeLight();
96 101
97 /** 102 /**
98 * Sets home led into a slow breathing state 103 * Sets home led into a slow breathing state
99 */ 104 */
100 DriverResult SetLedBusy(); 105 Common::Input::DriverResult SetLedBusy();
101 106
102 /** 107 /**
103 * Sets the 4 player leds on the joycon on a solid state 108 * Sets the 4 player leds on the joycon on a solid state
104 * @params bit flag containing the led state 109 * @params bit flag containing the led state
105 */ 110 */
106 DriverResult SetLedPattern(u8 leds); 111 Common::Input::DriverResult SetLedPattern(u8 leds);
107 112
108 /** 113 /**
109 * Sets the 4 player leds on the joycon on a blinking state 114 * Sets the 4 player leds on the joycon on a blinking state
110 * @returns bit flag containing the led state 115 * @returns bit flag containing the led state
111 */ 116 */
112 DriverResult SetLedBlinkPattern(u8 leds); 117 Common::Input::DriverResult SetLedBlinkPattern(u8 leds);
113}; 118};
114} // namespace InputCommon::Joycon 119} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp
index 731fd5981..68b0589e3 100644
--- a/src/input_common/helpers/joycon_protocol/irs.cpp
+++ b/src/input_common/helpers/joycon_protocol/irs.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <thread> 4#include "common/input.h"
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "input_common/helpers/joycon_protocol/irs.h" 6#include "input_common/helpers/joycon_protocol/irs.h"
7 7
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
10IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle) 10IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle)
11 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
12 12
13DriverResult IrsProtocol::EnableIrs() { 13Common::Input::DriverResult IrsProtocol::EnableIrs() {
14 LOG_INFO(Input, "Enable IRS"); 14 LOG_INFO(Input, "Enable IRS");
15 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 17
18 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); 19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
20 } 20 }
21 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
22 result = EnableMCU(true); 22 result = EnableMCU(true);
23 } 23 }
24 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); 25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
26 } 26 }
27 if (result == DriverResult::Success) { 27 if (result == Common::Input::DriverResult::Success) {
28 const MCUConfig config{ 28 const MCUConfig config{
29 .command = MCUCommand::ConfigureMCU, 29 .command = MCUCommand::ConfigureMCU,
30 .sub_command = MCUSubCommand::SetMCUMode, 30 .sub_command = MCUSubCommand::SetMCUMode,
@@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() {
34 34
35 result = ConfigureMCU(config); 35 result = ConfigureMCU(config);
36 } 36 }
37 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR); 38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR);
39 } 39 }
40 if (result == DriverResult::Success) { 40 if (result == Common::Input::DriverResult::Success) {
41 result = ConfigureIrs(); 41 result = ConfigureIrs();
42 } 42 }
43 if (result == DriverResult::Success) { 43 if (result == Common::Input::DriverResult::Success) {
44 result = WriteRegistersStep1(); 44 result = WriteRegistersStep1();
45 } 45 }
46 if (result == DriverResult::Success) { 46 if (result == Common::Input::DriverResult::Success) {
47 result = WriteRegistersStep2(); 47 result = WriteRegistersStep2();
48 } 48 }
49 49
@@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() {
52 return result; 52 return result;
53} 53}
54 54
55DriverResult IrsProtocol::DisableIrs() { 55Common::Input::DriverResult IrsProtocol::DisableIrs() {
56 LOG_DEBUG(Input, "Disable IRS"); 56 LOG_DEBUG(Input, "Disable IRS");
57 ScopedSetBlocking sb(this); 57 ScopedSetBlocking sb(this);
58 DriverResult result{DriverResult::Success}; 58 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
59 59
60 if (result == DriverResult::Success) { 60 if (result == Common::Input::DriverResult::Success) {
61 result = EnableMCU(false); 61 result = EnableMCU(false);
62 } 62 }
63 63
@@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() {
66 return result; 66 return result;
67} 67}
68 68
69DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { 69Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
70 irs_mode = mode; 70 irs_mode = mode;
71 switch (format) { 71 switch (format) {
72 case IrsResolution::Size320x240: 72 case IrsResolution::Size320x240:
@@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
103 return EnableIrs(); 103 return EnableIrs();
104 } 104 }
105 105
106 return DriverResult::Success; 106 return Common::Input::DriverResult::Success;
107} 107}
108 108
109DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { 109Common::Input::DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
110 const u8 next_packet_fragment = 110 const u8 next_packet_fragment =
111 static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1)); 111 static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1));
112 112
@@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
129 return RequestFrame(packet_fragment); 129 return RequestFrame(packet_fragment);
130} 130}
131 131
132DriverResult IrsProtocol::ConfigureIrs() { 132Common::Input::DriverResult IrsProtocol::ConfigureIrs() {
133 LOG_DEBUG(Input, "Configure IRS"); 133 LOG_DEBUG(Input, "Configure IRS");
134 constexpr std::size_t max_tries = 28; 134 constexpr std::size_t max_tries = 28;
135 SubCommandResponse output{}; 135 SubCommandResponse output{};
@@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() {
152 do { 152 do {
153 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 153 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
154 154
155 if (result != DriverResult::Success) { 155 if (result != Common::Input::DriverResult::Success) {
156 return result; 156 return result;
157 } 157 }
158 if (tries++ >= max_tries) { 158 if (tries++ >= max_tries) {
159 return DriverResult::WrongReply; 159 return Common::Input::DriverResult::WrongReply;
160 } 160 }
161 } while (output.command_data[0] != 0x0b); 161 } while (output.command_data[0] != 0x0b);
162 162
163 return DriverResult::Success; 163 return Common::Input::DriverResult::Success;
164} 164}
165 165
166DriverResult IrsProtocol::WriteRegistersStep1() { 166Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() {
167 LOG_DEBUG(Input, "WriteRegistersStep1"); 167 LOG_DEBUG(Input, "WriteRegistersStep1");
168 DriverResult result{DriverResult::Success}; 168 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
169 constexpr std::size_t max_tries = 28; 169 constexpr std::size_t max_tries = 28;
170 SubCommandResponse output{}; 170 SubCommandResponse output{};
171 std::size_t tries = 0; 171 std::size_t tries = 0;
@@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
197 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); 197 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
198 mcu_request[37] = 0xFF; 198 mcu_request[37] = 0xFF;
199 199
200 if (result != DriverResult::Success) { 200 if (result != Common::Input::DriverResult::Success) {
201 return result; 201 return result;
202 } 202 }
203 203
@@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
205 result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 205 result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
206 206
207 // First time we need to set the report mode 207 // First time we need to set the report mode
208 if (result == DriverResult::Success && tries == 0) { 208 if (result == Common::Input::DriverResult::Success && tries == 0) {
209 result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); 209 result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
210 } 210 }
211 if (result == DriverResult::Success && tries == 0) { 211 if (result == Common::Input::DriverResult::Success && tries == 0) {
212 GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); 212 GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output);
213 } 213 }
214 214
215 if (result != DriverResult::Success) { 215 if (result != Common::Input::DriverResult::Success) {
216 return result; 216 return result;
217 } 217 }
218 if (tries++ >= max_tries) { 218 if (tries++ >= max_tries) {
219 return DriverResult::WrongReply; 219 return Common::Input::DriverResult::WrongReply;
220 } 220 }
221 } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && 221 } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
222 output.command_data[0] != 0x23); 222 output.command_data[0] != 0x23);
223 223
224 return DriverResult::Success; 224 return Common::Input::DriverResult::Success;
225} 225}
226 226
227DriverResult IrsProtocol::WriteRegistersStep2() { 227Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() {
228 LOG_DEBUG(Input, "WriteRegistersStep2"); 228 LOG_DEBUG(Input, "WriteRegistersStep2");
229 constexpr std::size_t max_tries = 28; 229 constexpr std::size_t max_tries = 28;
230 SubCommandResponse output{}; 230 SubCommandResponse output{};
@@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
255 do { 255 do {
256 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 256 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
257 257
258 if (result != DriverResult::Success) { 258 if (result != Common::Input::DriverResult::Success) {
259 return result; 259 return result;
260 } 260 }
261 if (tries++ >= max_tries) { 261 if (tries++ >= max_tries) {
262 return DriverResult::WrongReply; 262 return Common::Input::DriverResult::WrongReply;
263 } 263 }
264 } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23); 264 } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
265 265
266 return DriverResult::Success; 266 return Common::Input::DriverResult::Success;
267} 267}
268 268
269DriverResult IrsProtocol::RequestFrame(u8 frame) { 269Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) {
270 std::array<u8, 38> mcu_request{}; 270 std::array<u8, 38> mcu_request{};
271 mcu_request[3] = frame; 271 mcu_request[3] = frame;
272 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); 272 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
@@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) {
274 return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); 274 return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
275} 275}
276 276
277DriverResult IrsProtocol::ResendFrame(u8 frame) { 277Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) {
278 std::array<u8, 38> mcu_request{}; 278 std::array<u8, 38> mcu_request{};
279 mcu_request[1] = 0x1; 279 mcu_request[1] = 0x1;
280 mcu_request[2] = frame; 280 mcu_request[2] = frame;
diff --git a/src/input_common/helpers/joycon_protocol/irs.h b/src/input_common/helpers/joycon_protocol/irs.h
index 76dfa02ea..714cbb6b2 100644
--- a/src/input_common/helpers/joycon_protocol/irs.h
+++ b/src/input_common/helpers/joycon_protocol/irs.h
@@ -13,19 +13,23 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class IrsProtocol final : private JoyconCommonProtocol { 22class IrsProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableIrs(); 26 Common::Input::DriverResult EnableIrs();
23 27
24 DriverResult DisableIrs(); 28 Common::Input::DriverResult DisableIrs();
25 29
26 DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); 30 Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
27 31
28 DriverResult RequestImage(std::span<u8> buffer); 32 Common::Input::DriverResult RequestImage(std::span<u8> buffer);
29 33
30 std::vector<u8> GetImage() const; 34 std::vector<u8> GetImage() const;
31 35
@@ -34,13 +38,13 @@ public:
34 bool IsEnabled() const; 38 bool IsEnabled() const;
35 39
36private: 40private:
37 DriverResult ConfigureIrs(); 41 Common::Input::DriverResult ConfigureIrs();
38 42
39 DriverResult WriteRegistersStep1(); 43 Common::Input::DriverResult WriteRegistersStep1();
40 DriverResult WriteRegistersStep2(); 44 Common::Input::DriverResult WriteRegistersStep2();
41 45
42 DriverResult RequestFrame(u8 frame); 46 Common::Input::DriverResult RequestFrame(u8 frame);
43 DriverResult ResendFrame(u8 frame); 47 Common::Input::DriverResult ResendFrame(u8 frame);
44 48
45 IrsMode irs_mode{IrsMode::ImageTransfer}; 49 IrsMode irs_mode{IrsMode::ImageTransfer};
46 IrsResolution resolution{IrsResolution::Size40x30}; 50 IrsResolution resolution{IrsResolution::Size40x30};
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index 5007b0e18..77a43c67a 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -24,6 +24,7 @@ constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x
24using MacAddress = std::array<u8, 6>; 24using MacAddress = std::array<u8, 6>;
25using SerialNumber = std::array<u8, 15>; 25using SerialNumber = std::array<u8, 15>;
26using TagUUID = std::array<u8, 7>; 26using TagUUID = std::array<u8, 7>;
27using MifareUUID = std::array<u8, 4>;
27 28
28enum class ControllerType : u8 { 29enum class ControllerType : u8 {
29 None = 0x00, 30 None = 0x00,
@@ -307,6 +308,19 @@ enum class NFCStatus : u8 {
307 WriteDone = 0x05, 308 WriteDone = 0x05,
308 TagLost = 0x07, 309 TagLost = 0x07,
309 WriteReady = 0x09, 310 WriteReady = 0x09,
311 MifareDone = 0x10,
312};
313
314enum class MifareCmd : u8 {
315 None = 0x00,
316 Read = 0x30,
317 AuthA = 0x60,
318 AuthB = 0x61,
319 Write = 0xA0,
320 Transfer = 0xB0,
321 Decrement = 0xC0,
322 Increment = 0xC1,
323 Store = 0xC2
310}; 324};
311 325
312enum class IrsMode : u8 { 326enum class IrsMode : u8 {
@@ -388,23 +402,6 @@ enum class ExternalDeviceId : u16 {
388 Starlink = 0x2800, 402 Starlink = 0x2800,
389}; 403};
390 404
391enum class DriverResult {
392 Success,
393 WrongReply,
394 Timeout,
395 InvalidParameters,
396 UnsupportedControllerType,
397 HandleInUse,
398 ErrorReadingData,
399 ErrorWritingData,
400 NoDeviceDetected,
401 InvalidHandle,
402 NotSupported,
403 Disabled,
404 Delayed,
405 Unknown,
406};
407
408struct MotionSensorCalibration { 405struct MotionSensorCalibration {
409 s16 offset; 406 s16 offset;
410 s16 scale; 407 s16 scale;
@@ -592,6 +589,14 @@ struct NFCWriteCommandData {
592static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); 589static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size");
593#pragma pack(pop) 590#pragma pack(pop)
594 591
592struct MifareCommandData {
593 u8 unknown1;
594 u8 unknown2;
595 u8 number_of_short_bytes;
596 MifareUUID uid;
597};
598static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size");
599
595struct NFCPollingCommandData { 600struct NFCPollingCommandData {
596 u8 enable_mifare; 601 u8 enable_mifare;
597 u8 unknown_1; 602 u8 unknown_1;
@@ -629,6 +634,41 @@ struct NFCWritePackage {
629 std::array<NFCDataChunk, 4> data_chunks; 634 std::array<NFCDataChunk, 4> data_chunks;
630}; 635};
631 636
637struct MifareReadChunk {
638 MifareCmd command;
639 std::array<u8, 0x6> sector_key;
640 u8 sector;
641};
642
643struct MifareWriteChunk {
644 MifareCmd command;
645 std::array<u8, 0x6> sector_key;
646 u8 sector;
647 std::array<u8, 0x10> data;
648};
649
650struct MifareReadData {
651 u8 sector;
652 std::array<u8, 0x10> data;
653};
654
655struct MifareReadPackage {
656 MifareCommandData command_data;
657 std::array<MifareReadChunk, 0x10> data_chunks;
658};
659
660struct MifareWritePackage {
661 MifareCommandData command_data;
662 std::array<MifareWriteChunk, 0x10> data_chunks;
663};
664
665struct TagInfo {
666 u8 uuid_length;
667 u8 protocol;
668 u8 tag_type;
669 std::array<u8, 10> uuid;
670};
671
632struct IrsConfigure { 672struct IrsConfigure {
633 MCUCommand command; 673 MCUCommand command;
634 MCUSubCommand sub_command; 674 MCUSubCommand sub_command;
@@ -744,7 +784,7 @@ struct JoyconCallbacks {
744 std::function<void(int, f32)> on_stick_data; 784 std::function<void(int, f32)> on_stick_data;
745 std::function<void(int, const MotionData&)> on_motion_data; 785 std::function<void(int, const MotionData&)> on_motion_data;
746 std::function<void(f32)> on_ring_data; 786 std::function<void(f32)> on_ring_data;
747 std::function<void(const std::vector<u8>&)> on_amiibo_data; 787 std::function<void(const Joycon::TagInfo&)> on_amiibo_data;
748 std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; 788 std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data;
749}; 789};
750 790
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp
index f7058c4a7..09953394b 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <thread> 4#include "common/input.h"
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "input_common/helpers/joycon_protocol/nfc.h" 6#include "input_common/helpers/joycon_protocol/nfc.h"
7 7
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
10NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) 10NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle)
11 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
12 12
13DriverResult NfcProtocol::EnableNfc() { 13Common::Input::DriverResult NfcProtocol::EnableNfc() {
14 LOG_INFO(Input, "Enable NFC"); 14 LOG_INFO(Input, "Enable NFC");
15 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 17
18 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); 19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
20 } 20 }
21 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
22 result = EnableMCU(true); 22 result = EnableMCU(true);
23 } 23 }
24 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); 25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
26 } 26 }
27 if (result == DriverResult::Success) { 27 if (result == Common::Input::DriverResult::Success) {
28 const MCUConfig config{ 28 const MCUConfig config{
29 .command = MCUCommand::ConfigureMCU, 29 .command = MCUCommand::ConfigureMCU,
30 .sub_command = MCUSubCommand::SetMCUMode, 30 .sub_command = MCUSubCommand::SetMCUMode,
@@ -34,123 +34,240 @@ DriverResult NfcProtocol::EnableNfc() {
34 34
35 result = ConfigureMCU(config); 35 result = ConfigureMCU(config);
36 } 36 }
37 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC); 38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC);
39 } 39 }
40 if (result == DriverResult::Success) { 40 if (result == Common::Input::DriverResult::Success) {
41 result = WaitUntilNfcIs(NFCStatus::Ready); 41 result = WaitUntilNfcIs(NFCStatus::Ready);
42 } 42 }
43 if (result == Common::Input::DriverResult::Success) {
44 MCUCommandResponse output{};
45 result = SendStopPollingRequest(output);
46 }
47 if (result == Common::Input::DriverResult::Success) {
48 result = WaitUntilNfcIs(NFCStatus::Ready);
49 }
50 if (result == Common::Input::DriverResult::Success) {
51 is_enabled = true;
52 }
43 53
44 return result; 54 return result;
45} 55}
46 56
47DriverResult NfcProtocol::DisableNfc() { 57Common::Input::DriverResult NfcProtocol::DisableNfc() {
48 LOG_DEBUG(Input, "Disable NFC"); 58 LOG_DEBUG(Input, "Disable NFC");
49 ScopedSetBlocking sb(this); 59 ScopedSetBlocking sb(this);
50 DriverResult result{DriverResult::Success}; 60 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
51 61
52 if (result == DriverResult::Success) { 62 if (result == Common::Input::DriverResult::Success) {
53 result = EnableMCU(false); 63 result = EnableMCU(false);
54 } 64 }
55 65
56 is_enabled = false; 66 is_enabled = false;
67 is_polling = false;
57 68
58 return result; 69 return result;
59} 70}
60 71
61DriverResult NfcProtocol::StartNFCPollingMode() { 72Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() {
62 LOG_DEBUG(Input, "Start NFC pooling Mode"); 73 LOG_DEBUG(Input, "Start NFC polling Mode");
63 ScopedSetBlocking sb(this); 74 ScopedSetBlocking sb(this);
64 DriverResult result{DriverResult::Success}; 75 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
65 76
66 if (result == DriverResult::Success) { 77 if (result == Common::Input::DriverResult::Success) {
67 MCUCommandResponse output{}; 78 MCUCommandResponse output{};
68 result = SendStopPollingRequest(output); 79 result = SendStartPollingRequest(output);
69 } 80 }
70 if (result == DriverResult::Success) { 81 if (result == Common::Input::DriverResult::Success) {
71 result = WaitUntilNfcIs(NFCStatus::Ready); 82 result = WaitUntilNfcIs(NFCStatus::Polling);
83 }
84 if (result == Common::Input::DriverResult::Success) {
85 is_polling = true;
72 } 86 }
73 if (result == DriverResult::Success) { 87
88 return result;
89}
90
91Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() {
92 LOG_DEBUG(Input, "Stop NFC polling Mode");
93 ScopedSetBlocking sb(this);
94 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
95
96 if (result == Common::Input::DriverResult::Success) {
74 MCUCommandResponse output{}; 97 MCUCommandResponse output{};
75 result = SendStartPollingRequest(output); 98 result = SendStopPollingRequest(output);
76 } 99 }
77 if (result == DriverResult::Success) { 100 if (result == Common::Input::DriverResult::Success) {
78 result = WaitUntilNfcIs(NFCStatus::Polling); 101 result = WaitUntilNfcIs(NFCStatus::WriteReady);
79 } 102 }
80 if (result == DriverResult::Success) { 103 if (result == Common::Input::DriverResult::Success) {
81 is_enabled = true; 104 is_polling = false;
82 } 105 }
83 106
84 return result; 107 return result;
85} 108}
86 109
87DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { 110Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
88 if (update_counter++ < AMIIBO_UPDATE_DELAY) { 111 if (update_counter++ < AMIIBO_UPDATE_DELAY) {
89 return DriverResult::Delayed; 112 return Common::Input::DriverResult::Delayed;
90 } 113 }
91 update_counter = 0; 114 update_counter = 0;
92 115
93 LOG_DEBUG(Input, "Scan for amiibos"); 116 LOG_DEBUG(Input, "Scan for amiibos");
94 ScopedSetBlocking sb(this); 117 ScopedSetBlocking sb(this);
95 DriverResult result{DriverResult::Success}; 118 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
96 TagFoundData tag_data{}; 119 TagFoundData tag_data{};
97 120
98 if (result == DriverResult::Success) { 121 if (result == Common::Input::DriverResult::Success) {
99 result = IsTagInRange(tag_data); 122 result = IsTagInRange(tag_data);
100 } 123 }
101 124
102 if (result == DriverResult::Success) { 125 if (result == Common::Input::DriverResult::Success) {
126 tag_info = {
127 .uuid_length = tag_data.uuid_size,
128 .protocol = 1,
129 .tag_type = tag_data.type,
130 .uuid = {},
131 };
132
133 memcpy(tag_info.uuid.data(), tag_data.uuid.data(), tag_data.uuid_size);
134
135 // Investigate why mifare type is not correct
136 if (tag_info.tag_type == 144) {
137 tag_info.tag_type = 1U << 6;
138 }
139
103 std::string uuid_string; 140 std::string uuid_string;
104 for (auto& content : tag_data.uuid) { 141 for (auto& content : tag_data.uuid) {
105 uuid_string += fmt::format(" {:02x}", content); 142 uuid_string += fmt::format(" {:02x}", content);
106 } 143 }
107 LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string); 144 LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string);
145 }
146
147 return result;
148}
149
150Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
151 LOG_DEBUG(Input, "Scan for amiibos");
152 ScopedSetBlocking sb(this);
153 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
154 TagFoundData tag_data{};
155
156 if (result == Common::Input::DriverResult::Success) {
157 result = IsTagInRange(tag_data, 7);
158 }
159
160 if (result == Common::Input::DriverResult::Success) {
108 result = GetAmiiboData(data); 161 result = GetAmiiboData(data);
109 } 162 }
110 163
111 return result; 164 return result;
112} 165}
113 166
114DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { 167Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
115 LOG_DEBUG(Input, "Write amiibo"); 168 LOG_DEBUG(Input, "Write amiibo");
116 ScopedSetBlocking sb(this); 169 ScopedSetBlocking sb(this);
117 DriverResult result{DriverResult::Success}; 170 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
118 TagUUID tag_uuid = GetTagUUID(data); 171 TagUUID tag_uuid = GetTagUUID(data);
119 TagFoundData tag_data{}; 172 TagFoundData tag_data{};
120 173
121 if (result == DriverResult::Success) { 174 if (result == Common::Input::DriverResult::Success) {
122 result = IsTagInRange(tag_data, 7); 175 result = IsTagInRange(tag_data, 7);
123 } 176 }
124 if (result == DriverResult::Success) { 177 if (result == Common::Input::DriverResult::Success) {
125 if (tag_data.uuid != tag_uuid) { 178 if (tag_data.uuid != tag_uuid) {
126 result = DriverResult::InvalidParameters; 179 result = Common::Input::DriverResult::InvalidParameters;
127 } 180 }
128 } 181 }
129 if (result == DriverResult::Success) { 182 if (result == Common::Input::DriverResult::Success) {
130 MCUCommandResponse output{}; 183 MCUCommandResponse output{};
131 result = SendStopPollingRequest(output); 184 result = SendStopPollingRequest(output);
132 } 185 }
133 if (result == DriverResult::Success) { 186 if (result == Common::Input::DriverResult::Success) {
134 result = WaitUntilNfcIs(NFCStatus::Ready); 187 result = WaitUntilNfcIs(NFCStatus::Ready);
135 } 188 }
136 if (result == DriverResult::Success) { 189 if (result == Common::Input::DriverResult::Success) {
137 MCUCommandResponse output{}; 190 MCUCommandResponse output{};
138 result = SendStartPollingRequest(output, true); 191 result = SendStartPollingRequest(output, true);
139 } 192 }
140 if (result == DriverResult::Success) { 193 if (result == Common::Input::DriverResult::Success) {
141 result = WaitUntilNfcIs(NFCStatus::WriteReady); 194 result = WaitUntilNfcIs(NFCStatus::WriteReady);
142 } 195 }
143 if (result == DriverResult::Success) { 196 if (result == Common::Input::DriverResult::Success) {
144 result = WriteAmiiboData(tag_uuid, data); 197 result = WriteAmiiboData(tag_uuid, data);
145 } 198 }
146 if (result == DriverResult::Success) { 199 if (result == Common::Input::DriverResult::Success) {
147 result = WaitUntilNfcIs(NFCStatus::WriteDone); 200 result = WaitUntilNfcIs(NFCStatus::WriteDone);
148 } 201 }
149 if (result == DriverResult::Success) { 202 if (result == Common::Input::DriverResult::Success) {
203 MCUCommandResponse output{};
204 result = SendStopPollingRequest(output);
205 }
206
207 return result;
208}
209
210Common::Input::DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
211 std::span<MifareReadData> out_data) {
212 LOG_DEBUG(Input, "Read mifare");
213 ScopedSetBlocking sb(this);
214 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
215 TagFoundData tag_data{};
216 MifareUUID tag_uuid{};
217
218 if (result == Common::Input::DriverResult::Success) {
219 result = IsTagInRange(tag_data, 7);
220 }
221 if (result == Common::Input::DriverResult::Success) {
222 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
223 result = GetMifareData(tag_uuid, read_request, out_data);
224 }
225 if (result == Common::Input::DriverResult::Success) {
150 MCUCommandResponse output{}; 226 MCUCommandResponse output{};
151 result = SendStopPollingRequest(output); 227 result = SendStopPollingRequest(output);
152 } 228 }
229 if (result == Common::Input::DriverResult::Success) {
230 result = WaitUntilNfcIs(NFCStatus::Ready);
231 }
232 if (result == Common::Input::DriverResult::Success) {
233 MCUCommandResponse output{};
234 result = SendStartPollingRequest(output, true);
235 }
236 if (result == Common::Input::DriverResult::Success) {
237 result = WaitUntilNfcIs(NFCStatus::WriteReady);
238 }
239 return result;
240}
241
242Common::Input::DriverResult NfcProtocol::WriteMifare(
243 std::span<const MifareWriteChunk> write_request) {
244 LOG_DEBUG(Input, "Write mifare");
245 ScopedSetBlocking sb(this);
246 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
247 TagFoundData tag_data{};
248 MifareUUID tag_uuid{};
153 249
250 if (result == Common::Input::DriverResult::Success) {
251 result = IsTagInRange(tag_data, 7);
252 }
253 if (result == Common::Input::DriverResult::Success) {
254 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
255 result = WriteMifareData(tag_uuid, write_request);
256 }
257 if (result == Common::Input::DriverResult::Success) {
258 MCUCommandResponse output{};
259 result = SendStopPollingRequest(output);
260 }
261 if (result == Common::Input::DriverResult::Success) {
262 result = WaitUntilNfcIs(NFCStatus::Ready);
263 }
264 if (result == Common::Input::DriverResult::Success) {
265 MCUCommandResponse output{};
266 result = SendStartPollingRequest(output, true);
267 }
268 if (result == Common::Input::DriverResult::Success) {
269 result = WaitUntilNfcIs(NFCStatus::WriteReady);
270 }
154 return result; 271 return result;
155} 272}
156 273
@@ -161,17 +278,17 @@ bool NfcProtocol::HasAmiibo() {
161 update_counter = 0; 278 update_counter = 0;
162 279
163 ScopedSetBlocking sb(this); 280 ScopedSetBlocking sb(this);
164 DriverResult result{DriverResult::Success}; 281 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
165 TagFoundData tag_data{}; 282 TagFoundData tag_data{};
166 283
167 if (result == DriverResult::Success) { 284 if (result == Common::Input::DriverResult::Success) {
168 result = IsTagInRange(tag_data, 7); 285 result = IsTagInRange(tag_data, 7);
169 } 286 }
170 287
171 return result == DriverResult::Success; 288 return result == Common::Input::DriverResult::Success;
172} 289}
173 290
174DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { 291Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
175 constexpr std::size_t timeout_limit = 10; 292 constexpr std::size_t timeout_limit = 10;
176 MCUCommandResponse output{}; 293 MCUCommandResponse output{};
177 std::size_t tries = 0; 294 std::size_t tries = 0;
@@ -179,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
179 do { 296 do {
180 auto result = SendNextPackageRequest(output, {}); 297 auto result = SendNextPackageRequest(output, {});
181 298
182 if (result != DriverResult::Success) { 299 if (result != Common::Input::DriverResult::Success) {
183 return result; 300 return result;
184 } 301 }
185 if (tries++ > timeout_limit) { 302 if (tries++ > timeout_limit) {
186 return DriverResult::Timeout; 303 return Common::Input::DriverResult::Timeout;
187 } 304 }
188 } while (output.mcu_report != MCUReport::NFCState || 305 } while (output.mcu_report != MCUReport::NFCState ||
189 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || 306 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
190 output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status)); 307 output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status));
191 308
192 return DriverResult::Success; 309 return Common::Input::DriverResult::Success;
193} 310}
194 311
195DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) { 312Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data,
313 std::size_t timeout_limit) {
196 MCUCommandResponse output{}; 314 MCUCommandResponse output{};
197 std::size_t tries = 0; 315 std::size_t tries = 0;
198 316
199 do { 317 do {
200 const auto result = SendNextPackageRequest(output, {}); 318 const auto result = SendNextPackageRequest(output, {});
201 if (result != DriverResult::Success) { 319 if (result != Common::Input::DriverResult::Success) {
202 return result; 320 return result;
203 } 321 }
204 if (tries++ > timeout_limit) { 322 if (tries++ > timeout_limit) {
205 return DriverResult::Timeout; 323 return Common::Input::DriverResult::Timeout;
206 } 324 }
207 } while (output.mcu_report != MCUReport::NFCState || 325 } while (output.mcu_report != MCUReport::NFCState ||
208 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || 326 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
@@ -212,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l
212 data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID))); 330 data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID)));
213 memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size()); 331 memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
214 332
215 return DriverResult::Success; 333 return Common::Input::DriverResult::Success;
216} 334}
217 335
218DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { 336Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
219 constexpr std::size_t timeout_limit = 60; 337 constexpr std::size_t timeout_limit = 60;
220 MCUCommandResponse output{}; 338 MCUCommandResponse output{};
221 std::size_t tries = 0; 339 std::size_t tries = 0;
@@ -224,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
224 std::size_t ntag_buffer_pos = 0; 342 std::size_t ntag_buffer_pos = 0;
225 auto result = SendReadAmiiboRequest(output, NFCPages::Block135); 343 auto result = SendReadAmiiboRequest(output, NFCPages::Block135);
226 344
227 if (result != DriverResult::Success) { 345 if (result != Common::Input::DriverResult::Success) {
228 return result; 346 return result;
229 } 347 }
230 348
@@ -233,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
233 result = SendNextPackageRequest(output, package_index); 351 result = SendNextPackageRequest(output, package_index);
234 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 352 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
235 353
236 if (result != DriverResult::Success) { 354 if (result != Common::Input::DriverResult::Success) {
237 return result; 355 return result;
238 } 356 }
239 357
240 if ((output.mcu_report == MCUReport::NFCReadData || 358 if ((output.mcu_report == MCUReport::NFCReadData ||
241 output.mcu_report == MCUReport::NFCState) && 359 output.mcu_report == MCUReport::NFCState) &&
242 nfc_status == NFCStatus::TagLost) { 360 nfc_status == NFCStatus::TagLost) {
243 return DriverResult::ErrorReadingData; 361 return Common::Input::DriverResult::ErrorReadingData;
244 } 362 }
245 363
246 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { 364 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -259,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
259 377
260 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { 378 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
261 LOG_INFO(Input, "Finished reading amiibo"); 379 LOG_INFO(Input, "Finished reading amiibo");
262 return DriverResult::Success; 380 return Common::Input::DriverResult::Success;
263 } 381 }
264 } 382 }
265 383
266 return DriverResult::Timeout; 384 return Common::Input::DriverResult::Timeout;
267} 385}
268 386
269DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data) { 387Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid,
388 std::span<const u8> data) {
270 constexpr std::size_t timeout_limit = 60; 389 constexpr std::size_t timeout_limit = 60;
271 const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data); 390 const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data);
272 const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data); 391 const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data);
@@ -281,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
281 400
282 auto result = SendWriteAmiiboRequest(output, tag_uuid); 401 auto result = SendWriteAmiiboRequest(output, tag_uuid);
283 402
284 if (result != DriverResult::Success) { 403 if (result != Common::Input::DriverResult::Success) {
285 return result; 404 return result;
286 } 405 }
287 406
@@ -290,14 +409,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
290 result = SendNextPackageRequest(output, package_index); 409 result = SendNextPackageRequest(output, package_index);
291 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 410 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
292 411
293 if (result != DriverResult::Success) { 412 if (result != Common::Input::DriverResult::Success) {
294 return result; 413 return result;
295 } 414 }
296 415
297 if ((output.mcu_report == MCUReport::NFCReadData || 416 if ((output.mcu_report == MCUReport::NFCReadData ||
298 output.mcu_report == MCUReport::NFCState) && 417 output.mcu_report == MCUReport::NFCState) &&
299 nfc_status == NFCStatus::TagLost) { 418 nfc_status == NFCStatus::TagLost) {
300 return DriverResult::ErrorReadingData; 419 return Common::Input::DriverResult::ErrorReadingData;
301 } 420 }
302 421
303 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { 422 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -326,7 +445,131 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
326 if ((output.mcu_report == MCUReport::NFCReadData || 445 if ((output.mcu_report == MCUReport::NFCReadData ||
327 output.mcu_report == MCUReport::NFCState) && 446 output.mcu_report == MCUReport::NFCState) &&
328 nfc_status == NFCStatus::TagLost) { 447 nfc_status == NFCStatus::TagLost) {
329 return DriverResult::ErrorReadingData; 448 return Common::Input::DriverResult::ErrorReadingData;
449 }
450
451 // Increase position when data is confirmed by the joycon
452 if (output.mcu_report == MCUReport::NFCState &&
453 (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 &&
454 output.mcu_data[3] == block_id) {
455 block_id++;
456 current_position = next_position;
457 }
458 }
459
460 return result;
461}
462
463Common::Input::DriverResult NfcProtocol::GetMifareData(
464 const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request,
465 std::span<MifareReadData> out_data) {
466 constexpr std::size_t timeout_limit = 60;
467 const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request);
468 const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data);
469 std::span<const u8> buffer(nfc_buffer_data);
470 Common::Input::DriverResult result = Common::Input::DriverResult::Success;
471 MCUCommandResponse output{};
472 u8 block_id = 1;
473 u8 package_index = 0;
474 std::size_t tries = 0;
475 std::size_t current_position = 0;
476
477 LOG_INFO(Input, "Reading Mifare data");
478
479 // Send data request. Nfc buffer size is 31, Send the data in smaller packages
480 while (current_position < buffer.size() && tries++ < timeout_limit) {
481 const std::size_t next_position =
482 std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size());
483 const std::size_t block_size = next_position - current_position;
484 const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data);
485
486 SendReadDataMifareRequest(output, block_id, is_last_packet,
487 buffer.subspan(current_position, block_size));
488
489 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
490
491 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
492 return Common::Input::DriverResult::ErrorReadingData;
493 }
494
495 // Increase position when data is confirmed by the joycon
496 if (output.mcu_report == MCUReport::NFCState &&
497 (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 &&
498 output.mcu_data[3] == block_id) {
499 block_id++;
500 current_position = next_position;
501 }
502 }
503
504 if (result != Common::Input::DriverResult::Success) {
505 return result;
506 }
507
508 // Wait for reply and save the output data
509 while (tries++ < timeout_limit) {
510 result = SendNextPackageRequest(output, package_index);
511 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
512
513 if (result != Common::Input::DriverResult::Success) {
514 return result;
515 }
516
517 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
518 return Common::Input::DriverResult::ErrorReadingData;
519 }
520
521 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
522 constexpr std::size_t DATA_LENGHT = 0x10 + 1;
523 constexpr std::size_t DATA_START = 11;
524 const u8 number_of_elements = output.mcu_data[10];
525 for (std::size_t i = 0; i < number_of_elements; i++) {
526 out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)];
527 memcpy(out_data[i].data.data(),
528 output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT),
529 sizeof(MifareReadData::data));
530 }
531 package_index++;
532 continue;
533 }
534
535 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) {
536 LOG_INFO(Input, "Finished reading mifare");
537 break;
538 }
539 }
540
541 return result;
542}
543
544Common::Input::DriverResult NfcProtocol::WriteMifareData(
545 const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> write_request) {
546 constexpr std::size_t timeout_limit = 60;
547 const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request);
548 const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data);
549 std::span<const u8> buffer(nfc_buffer_data);
550 Common::Input::DriverResult result = Common::Input::DriverResult::Success;
551 MCUCommandResponse output{};
552 u8 block_id = 1;
553 u8 package_index = 0;
554 std::size_t tries = 0;
555 std::size_t current_position = 0;
556
557 LOG_INFO(Input, "Writing Mifare data");
558
559 // Send data request. Nfc buffer size is 31, Send the data in smaller packages
560 while (current_position < buffer.size() && tries++ < timeout_limit) {
561 const std::size_t next_position =
562 std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size());
563 const std::size_t block_size = next_position - current_position;
564 const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data);
565
566 SendReadDataMifareRequest(output, block_id, is_last_packet,
567 buffer.subspan(current_position, block_size));
568
569 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
570
571 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
572 return Common::Input::DriverResult::ErrorReadingData;
330 } 573 }
331 574
332 // Increase position when data is confirmed by the joycon 575 // Increase position when data is confirmed by the joycon
@@ -338,11 +581,39 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
338 } 581 }
339 } 582 }
340 583
584 if (result != Common::Input::DriverResult::Success) {
585 return result;
586 }
587
588 // Wait for reply and ignore the output data
589 while (tries++ < timeout_limit) {
590 result = SendNextPackageRequest(output, package_index);
591 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
592
593 if (result != Common::Input::DriverResult::Success) {
594 return result;
595 }
596
597 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
598 return Common::Input::DriverResult::ErrorReadingData;
599 }
600
601 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
602 package_index++;
603 continue;
604 }
605
606 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) {
607 LOG_INFO(Input, "Finished writing mifare");
608 break;
609 }
610 }
611
341 return result; 612 return result;
342} 613}
343 614
344DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, 615Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
345 bool is_second_attempt) { 616 bool is_second_attempt) {
346 NFCRequestState request{ 617 NFCRequestState request{
347 .command_argument = NFCCommand::StartPolling, 618 .command_argument = NFCCommand::StartPolling,
348 .block_id = {}, 619 .block_id = {},
@@ -367,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
367 output); 638 output);
368} 639}
369 640
370DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { 641Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
371 NFCRequestState request{ 642 NFCRequestState request{
372 .command_argument = NFCCommand::StopPolling, 643 .command_argument = NFCCommand::StopPolling,
373 .block_id = {}, 644 .block_id = {},
@@ -385,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
385 output); 656 output);
386} 657}
387 658
388DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) { 659Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output,
660 u8 packet_id) {
389 NFCRequestState request{ 661 NFCRequestState request{
390 .command_argument = NFCCommand::StartWaitingRecieve, 662 .command_argument = NFCCommand::StartWaitingRecieve,
391 .block_id = {}, 663 .block_id = {},
@@ -403,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8
403 output); 675 output);
404} 676}
405 677
406DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { 678Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output,
679 NFCPages ntag_pages) {
407 NFCRequestState request{ 680 NFCRequestState request{
408 .command_argument = NFCCommand::ReadNtag, 681 .command_argument = NFCCommand::ReadNtag,
409 .block_id = {}, 682 .block_id = {},
@@ -428,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
428 output); 701 output);
429} 702}
430 703
431DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, 704Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
432 const TagUUID& tag_uuid) { 705 const TagUUID& tag_uuid) {
433 NFCRequestState request{ 706 NFCRequestState request{
434 .command_argument = NFCCommand::ReadNtag, 707 .command_argument = NFCCommand::ReadNtag,
435 .block_id = {}, 708 .block_id = {},
@@ -454,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
454 output); 727 output);
455} 728}
456 729
457DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, 730Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
458 bool is_last_packet, 731 u8 block_id,
459 std::span<const u8> data) { 732 bool is_last_packet,
733 std::span<const u8> data) {
460 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); 734 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
461 NFCRequestState request{ 735 NFCRequestState request{
462 .command_argument = NFCCommand::WriteNtag, 736 .command_argument = NFCCommand::WriteNtag,
@@ -477,6 +751,29 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
477 output); 751 output);
478} 752}
479 753
754Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output,
755 u8 block_id, bool is_last_packet,
756 std::span<const u8> data) {
757 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
758 NFCRequestState request{
759 .command_argument = NFCCommand::Mifare,
760 .block_id = block_id,
761 .packet_id = {},
762 .packet_flag =
763 is_last_packet ? MCUPacketFlag::LastCommandPacket : MCUPacketFlag::MorePacketsRemaining,
764 .data_length = static_cast<u8>(data_size),
765 .raw_data = {},
766 .crc = {},
767 };
768 memcpy(request.raw_data.data(), data.data(), data_size);
769
770 std::array<u8, sizeof(NFCRequestState)> request_data{};
771 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
772 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
773 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
774 output);
775}
776
480std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { 777std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const {
481 const std::size_t header_size = 778 const std::size_t header_size =
482 sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); 779 sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks);
@@ -498,6 +795,48 @@ std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& packag
498 return serialized_data; 795 return serialized_data;
499} 796}
500 797
798std::vector<u8> NfcProtocol::SerializeMifareReadPackage(const MifareReadPackage& package) const {
799 const std::size_t header_size = sizeof(MifareCommandData);
800 std::vector<u8> serialized_data(header_size);
801 std::size_t start_index = 0;
802
803 memcpy(serialized_data.data(), &package, header_size);
804 start_index += header_size;
805
806 for (const auto& data_chunk : package.data_chunks) {
807 const std::size_t chunk_size = sizeof(MifareReadChunk);
808 if (data_chunk.command == MifareCmd::None) {
809 continue;
810 }
811 serialized_data.resize(start_index + chunk_size);
812 memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size);
813 start_index += chunk_size;
814 }
815
816 return serialized_data;
817}
818
819std::vector<u8> NfcProtocol::SerializeMifareWritePackage(const MifareWritePackage& package) const {
820 const std::size_t header_size = sizeof(MifareCommandData);
821 std::vector<u8> serialized_data(header_size);
822 std::size_t start_index = 0;
823
824 memcpy(serialized_data.data(), &package, header_size);
825 start_index += header_size;
826
827 for (const auto& data_chunk : package.data_chunks) {
828 const std::size_t chunk_size = sizeof(MifareWriteChunk);
829 if (data_chunk.command == MifareCmd::None) {
830 continue;
831 }
832 serialized_data.resize(start_index + chunk_size);
833 memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size);
834 start_index += chunk_size;
835 }
836
837 return serialized_data;
838}
839
501NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, 840NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid,
502 std::span<const u8> data) const { 841 std::span<const u8> data) const {
503 return { 842 return {
@@ -527,6 +866,46 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid,
527 }; 866 };
528} 867}
529 868
869MifareReadPackage NfcProtocol::MakeMifareReadPackage(
870 const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request) const {
871 MifareReadPackage package{
872 .command_data{
873 .unknown1 = 0xd0,
874 .unknown2 = 0x07,
875 .number_of_short_bytes = static_cast<u8>(
876 ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID)) / 2),
877 .uid = tag_uuid,
878 },
879 .data_chunks = {},
880 };
881
882 for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) {
883 package.data_chunks[i] = read_request[i];
884 }
885
886 return package;
887}
888
889MifareWritePackage NfcProtocol::MakeMifareWritePackage(
890 const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> read_request) const {
891 MifareWritePackage package{
892 .command_data{
893 .unknown1 = 0xd0,
894 .unknown2 = 0x07,
895 .number_of_short_bytes = static_cast<u8>(
896 ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID) + 2) / 2),
897 .uid = tag_uuid,
898 },
899 .data_chunks = {},
900 };
901
902 for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) {
903 package.data_chunks[i] = read_request[i];
904 }
905
906 return package;
907}
908
530NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { 909NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const {
531 constexpr u8 NFC_PAGE_SIZE = 4; 910 constexpr u8 NFC_PAGE_SIZE = 4;
532 911
@@ -606,4 +985,8 @@ bool NfcProtocol::IsEnabled() const {
606 return is_enabled; 985 return is_enabled;
607} 986}
608 987
988bool NfcProtocol::IsPolling() const {
989 return is_polling;
990}
991
609} // namespace InputCommon::Joycon 992} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h
index eb58c427d..22db95170 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.h
+++ b/src/input_common/helpers/joycon_protocol/nfc.h
@@ -13,26 +13,41 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class NfcProtocol final : private JoyconCommonProtocol { 22class NfcProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableNfc(); 26 Common::Input::DriverResult EnableNfc();
27
28 Common::Input::DriverResult DisableNfc();
29
30 Common::Input::DriverResult StartNFCPollingMode();
31
32 Common::Input::DriverResult StopNFCPollingMode();
23 33
24 DriverResult DisableNfc(); 34 Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
25 35
26 DriverResult StartNFCPollingMode(); 36 Common::Input::DriverResult ReadAmiibo(std::vector<u8>& data);
27 37
28 DriverResult ScanAmiibo(std::vector<u8>& data); 38 Common::Input::DriverResult WriteAmiibo(std::span<const u8> data);
29 39
30 DriverResult WriteAmiibo(std::span<const u8> data); 40 Common::Input::DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
41 std::span<MifareReadData> out_data);
42
43 Common::Input::DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
31 44
32 bool HasAmiibo(); 45 bool HasAmiibo();
33 46
34 bool IsEnabled() const; 47 bool IsEnabled() const;
35 48
49 bool IsPolling() const;
50
36private: 51private:
37 // Number of times the function will be delayed until it outputs valid data 52 // Number of times the function will be delayed until it outputs valid data
38 static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; 53 static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15;
@@ -43,39 +58,64 @@ private:
43 TagUUID uuid; 58 TagUUID uuid;
44 }; 59 };
45 60
46 DriverResult WaitUntilNfcIs(NFCStatus status); 61 Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status);
62
63 Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
47 64
48 DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1); 65 Common::Input::DriverResult GetAmiiboData(std::vector<u8>& data);
49 66
50 DriverResult GetAmiiboData(std::vector<u8>& data); 67 Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
51 68
52 DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); 69 Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid,
70 std::span<const MifareReadChunk> read_request,
71 std::span<MifareReadData> out_data);
53 72
54 DriverResult SendStartPollingRequest(MCUCommandResponse& output, 73 Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid,
55 bool is_second_attempt = false); 74 std::span<const MifareWriteChunk> write_request);
56 75
57 DriverResult SendStopPollingRequest(MCUCommandResponse& output); 76 Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output,
77 bool is_second_attempt = false);
58 78
59 DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id); 79 Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output);
60 80
61 DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages); 81 Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
62 82
63 DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid); 83 Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output,
84 NFCPages ntag_pages);
64 85
65 DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, 86 Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output,
66 bool is_last_packet, std::span<const u8> data); 87 const TagUUID& tag_uuid);
88
89 Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
90 bool is_last_packet,
91 std::span<const u8> data);
92
93 Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
94 bool is_last_packet,
95 std::span<const u8> data);
67 96
68 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; 97 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const;
69 98
99 std::vector<u8> SerializeMifareReadPackage(const MifareReadPackage& package) const;
100
101 std::vector<u8> SerializeMifareWritePackage(const MifareWritePackage& package) const;
102
70 NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; 103 NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const;
71 104
72 NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; 105 NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const;
73 106
107 MifareReadPackage MakeMifareReadPackage(const MifareUUID& tag_uuid,
108 std::span<const MifareReadChunk> read_request) const;
109
110 MifareWritePackage MakeMifareWritePackage(const MifareUUID& tag_uuid,
111 std::span<const MifareWriteChunk> read_request) const;
112
74 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; 113 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const;
75 114
76 TagUUID GetTagUUID(std::span<const u8> data) const; 115 TagUUID GetTagUUID(std::span<const u8> data) const;
77 116
78 bool is_enabled{}; 117 bool is_enabled{};
118 bool is_polling{};
79 std::size_t update_counter{}; 119 std::size_t update_counter{};
80}; 120};
81 121
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp
index dca797f7a..1aab9e12a 100644
--- a/src/input_common/helpers/joycon_protocol/poller.cpp
+++ b/src/input_common/helpers/joycon_protocol/poller.cpp
@@ -70,8 +70,8 @@ void JoyconPoller::UpdateColor(const Color& color) {
70 callbacks.on_color_data(color); 70 callbacks.on_color_data(color);
71} 71}
72 72
73void JoyconPoller::UpdateAmiibo(const std::vector<u8>& amiibo_data) { 73void JoyconPoller::UpdateAmiibo(const Joycon::TagInfo& tag_info) {
74 callbacks.on_amiibo_data(amiibo_data); 74 callbacks.on_amiibo_data(tag_info);
75} 75}
76 76
77void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) { 77void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) {
diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h
index 0fa72c6db..3746abe5d 100644
--- a/src/input_common/helpers/joycon_protocol/poller.h
+++ b/src/input_common/helpers/joycon_protocol/poller.h
@@ -36,8 +36,8 @@ public:
36 36
37 void UpdateColor(const Color& color); 37 void UpdateColor(const Color& color);
38 void UpdateRing(s16 value, const RingStatus& ring_status); 38 void UpdateRing(s16 value, const RingStatus& ring_status);
39 void UpdateAmiibo(const std::vector<u8>& amiibo_data); 39 void UpdateAmiibo(const Joycon::TagInfo& tag_info);
40 void UpdateCamera(const std::vector<u8>& amiibo_data, IrsResolution format); 40 void UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format);
41 41
42private: 42private:
43 void UpdateActiveLeftPadInput(const InputReportActive& input, 43 void UpdateActiveLeftPadInput(const InputReportActive& input,
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp
index 190cef812..96414fb67 100644
--- a/src/input_common/helpers/joycon_protocol/ringcon.cpp
+++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/ringcon.h" 6#include "input_common/helpers/joycon_protocol/ringcon.h"
6 7
@@ -9,18 +10,18 @@ namespace InputCommon::Joycon {
9RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) 10RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle)
10 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
11 12
12DriverResult RingConProtocol::EnableRingCon() { 13Common::Input::DriverResult RingConProtocol::EnableRingCon() {
13 LOG_DEBUG(Input, "Enable Ringcon"); 14 LOG_DEBUG(Input, "Enable Ringcon");
14 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
15 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
16 17
17 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
18 result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); 19 result = SetReportMode(ReportMode::STANDARD_FULL_60HZ);
19 } 20 }
20 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
21 result = EnableMCU(true); 22 result = EnableMCU(true);
22 } 23 }
23 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
24 const MCUConfig config{ 25 const MCUConfig config{
25 .command = MCUCommand::ConfigureMCU, 26 .command = MCUCommand::ConfigureMCU,
26 .sub_command = MCUSubCommand::SetDeviceMode, 27 .sub_command = MCUSubCommand::SetDeviceMode,
@@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() {
33 return result; 34 return result;
34} 35}
35 36
36DriverResult RingConProtocol::DisableRingCon() { 37Common::Input::DriverResult RingConProtocol::DisableRingCon() {
37 LOG_DEBUG(Input, "Disable RingCon"); 38 LOG_DEBUG(Input, "Disable RingCon");
38 ScopedSetBlocking sb(this); 39 ScopedSetBlocking sb(this);
39 DriverResult result{DriverResult::Success}; 40 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
40 41
41 if (result == DriverResult::Success) { 42 if (result == Common::Input::DriverResult::Success) {
42 result = EnableMCU(false); 43 result = EnableMCU(false);
43 } 44 }
44 45
@@ -47,29 +48,29 @@ DriverResult RingConProtocol::DisableRingCon() {
47 return result; 48 return result;
48} 49}
49 50
50DriverResult RingConProtocol::StartRingconPolling() { 51Common::Input::DriverResult RingConProtocol::StartRingconPolling() {
51 LOG_DEBUG(Input, "Enable Ringcon"); 52 LOG_DEBUG(Input, "Enable Ringcon");
52 ScopedSetBlocking sb(this); 53 ScopedSetBlocking sb(this);
53 DriverResult result{DriverResult::Success}; 54 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
54 bool is_connected = false; 55 bool is_connected = false;
55 56
56 if (result == DriverResult::Success) { 57 if (result == Common::Input::DriverResult::Success) {
57 result = IsRingConnected(is_connected); 58 result = IsRingConnected(is_connected);
58 } 59 }
59 if (result == DriverResult::Success && is_connected) { 60 if (result == Common::Input::DriverResult::Success && is_connected) {
60 LOG_INFO(Input, "Ringcon detected"); 61 LOG_INFO(Input, "Ringcon detected");
61 result = ConfigureRing(); 62 result = ConfigureRing();
62 } 63 }
63 if (result == DriverResult::Success) { 64 if (result == Common::Input::DriverResult::Success) {
64 is_enabled = true; 65 is_enabled = true;
65 } 66 }
66 67
67 return result; 68 return result;
68} 69}
69 70
70DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { 71Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
71 LOG_DEBUG(Input, "IsRingConnected"); 72 LOG_DEBUG(Input, "IsRingConnected");
72 constexpr std::size_t max_tries = 28; 73 constexpr std::size_t max_tries = 42;
73 SubCommandResponse output{}; 74 SubCommandResponse output{};
74 std::size_t tries = 0; 75 std::size_t tries = 0;
75 is_connected = false; 76 is_connected = false;
@@ -77,20 +78,21 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
77 do { 78 do {
78 const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output); 79 const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
79 80
80 if (result != DriverResult::Success) { 81 if (result != Common::Input::DriverResult::Success &&
82 result != Common::Input::DriverResult::Timeout) {
81 return result; 83 return result;
82 } 84 }
83 85
84 if (tries++ >= max_tries) { 86 if (tries++ >= max_tries) {
85 return DriverResult::NoDeviceDetected; 87 return Common::Input::DriverResult::NoDeviceDetected;
86 } 88 }
87 } while (output.external_device_id != ExternalDeviceId::RingController); 89 } while (output.external_device_id != ExternalDeviceId::RingController);
88 90
89 is_connected = true; 91 is_connected = true;
90 return DriverResult::Success; 92 return Common::Input::DriverResult::Success;
91} 93}
92 94
93DriverResult RingConProtocol::ConfigureRing() { 95Common::Input::DriverResult RingConProtocol::ConfigureRing() {
94 LOG_DEBUG(Input, "ConfigureRing"); 96 LOG_DEBUG(Input, "ConfigureRing");
95 97
96 static constexpr std::array<u8, 37> ring_config{ 98 static constexpr std::array<u8, 37> ring_config{
@@ -98,9 +100,10 @@ DriverResult RingConProtocol::ConfigureRing() {
98 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, 100 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; 101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36};
100 102
101 const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); 103 const Common::Input::DriverResult result =
104 SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
102 105
103 if (result != DriverResult::Success) { 106 if (result != Common::Input::DriverResult::Success) {
104 return result; 107 return result;
105 } 108 }
106 109
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.h b/src/input_common/helpers/joycon_protocol/ringcon.h
index 6e858f3fc..9f0888de3 100644
--- a/src/input_common/helpers/joycon_protocol/ringcon.h
+++ b/src/input_common/helpers/joycon_protocol/ringcon.h
@@ -13,24 +13,28 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class RingConProtocol final : private JoyconCommonProtocol { 22class RingConProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableRingCon(); 26 Common::Input::DriverResult EnableRingCon();
23 27
24 DriverResult DisableRingCon(); 28 Common::Input::DriverResult DisableRingCon();
25 29
26 DriverResult StartRingconPolling(); 30 Common::Input::DriverResult StartRingconPolling();
27 31
28 bool IsEnabled() const; 32 bool IsEnabled() const;
29 33
30private: 34private:
31 DriverResult IsRingConnected(bool& is_connected); 35 Common::Input::DriverResult IsRingConnected(bool& is_connected);
32 36
33 DriverResult ConfigureRing(); 37 Common::Input::DriverResult ConfigureRing();
34 38
35 bool is_enabled{}; 39 bool is_enabled{};
36}; 40};
diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp
index 63b60c946..7647f505e 100644
--- a/src/input_common/helpers/joycon_protocol/rumble.cpp
+++ b/src/input_common/helpers/joycon_protocol/rumble.cpp
@@ -4,6 +4,7 @@
4#include <algorithm> 4#include <algorithm>
5#include <cmath> 5#include <cmath>
6 6
7#include "common/input.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "input_common/helpers/joycon_protocol/rumble.h" 9#include "input_common/helpers/joycon_protocol/rumble.h"
9 10
@@ -12,14 +13,14 @@ namespace InputCommon::Joycon {
12RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) 13RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle)
13 : JoyconCommonProtocol(std::move(handle)) {} 14 : JoyconCommonProtocol(std::move(handle)) {}
14 15
15DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { 16Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
16 LOG_DEBUG(Input, "Enable Rumble"); 17 LOG_DEBUG(Input, "Enable Rumble");
17 ScopedSetBlocking sb(this); 18 ScopedSetBlocking sb(this);
18 const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; 19 const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)};
19 return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer); 20 return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer);
20} 21}
21 22
22DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { 23Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
23 std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{}; 24 std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{};
24 25
25 if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { 26 if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) {
diff --git a/src/input_common/helpers/joycon_protocol/rumble.h b/src/input_common/helpers/joycon_protocol/rumble.h
index 6c12b7925..5e50e531a 100644
--- a/src/input_common/helpers/joycon_protocol/rumble.h
+++ b/src/input_common/helpers/joycon_protocol/rumble.h
@@ -13,15 +13,19 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class RumbleProtocol final : private JoyconCommonProtocol { 22class RumbleProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableRumble(bool is_enabled); 26 Common::Input::DriverResult EnableRumble(bool is_enabled);
23 27
24 DriverResult SendVibration(const VibrationValue& vibration); 28 Common::Input::DriverResult SendVibration(const VibrationValue& vibration);
25 29
26private: 30private:
27 u16 EncodeHighFrequency(f32 frequency) const; 31 u16 EncodeHighFrequency(f32 frequency) const;