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.cpp118
-rw-r--r--src/input_common/helpers/joycon_driver.h6
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h59
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp390
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h34
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.cpp4
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.h4
7 files changed, 588 insertions, 27 deletions
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index 95106f16d..2c8c66951 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "common/scope_exit.h"
5#include "common/swap.h" 6#include "common/swap.h"
6#include "common/thread.h" 7#include "common/thread.h"
7#include "input_common/helpers/joycon_driver.h" 8#include "input_common/helpers/joycon_driver.h"
@@ -112,7 +113,7 @@ DriverResult JoyconDriver::InitializeDevice() {
112 joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, 113 joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration,
113 right_stick_calibration, motion_calibration); 114 right_stick_calibration, motion_calibration);
114 115
115 // Start pooling for data 116 // Start polling for data
116 is_connected = true; 117 is_connected = true;
117 if (!input_thread_running) { 118 if (!input_thread_running) {
118 input_thread = 119 input_thread =
@@ -208,7 +209,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
208 joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); 209 joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat());
209 } 210 }
210 211
211 if (nfc_protocol->IsEnabled()) { 212 if (nfc_protocol->IsPolling()) {
212 if (amiibo_detected) { 213 if (amiibo_detected) {
213 if (!nfc_protocol->HasAmiibo()) { 214 if (!nfc_protocol->HasAmiibo()) {
214 joycon_poller->UpdateAmiibo({}); 215 joycon_poller->UpdateAmiibo({});
@@ -218,10 +219,10 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
218 } 219 }
219 220
220 if (!amiibo_detected) { 221 if (!amiibo_detected) {
221 std::vector<u8> data(0x21C); 222 Joycon::TagInfo tag_info;
222 const auto result = nfc_protocol->ScanAmiibo(data); 223 const auto result = nfc_protocol->GetTagInfo(tag_info);
223 if (result == DriverResult::Success) { 224 if (result == DriverResult::Success) {
224 joycon_poller->UpdateAmiibo(data); 225 joycon_poller->UpdateAmiibo(tag_info);
225 amiibo_detected = true; 226 amiibo_detected = true;
226 } 227 }
227 } 228 }
@@ -247,6 +248,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
247} 248}
248 249
249DriverResult JoyconDriver::SetPollingMode() { 250DriverResult JoyconDriver::SetPollingMode() {
251 SCOPE_EXIT({ disable_input_thread = false; });
250 disable_input_thread = true; 252 disable_input_thread = true;
251 253
252 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); 254 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration);
@@ -276,7 +278,6 @@ DriverResult JoyconDriver::SetPollingMode() {
276 if (irs_enabled && supported_features.irs) { 278 if (irs_enabled && supported_features.irs) {
277 auto result = irs_protocol->EnableIrs(); 279 auto result = irs_protocol->EnableIrs();
278 if (result == DriverResult::Success) { 280 if (result == DriverResult::Success) {
279 disable_input_thread = false;
280 return result; 281 return result;
281 } 282 }
282 irs_protocol->DisableIrs(); 283 irs_protocol->DisableIrs();
@@ -286,10 +287,6 @@ DriverResult JoyconDriver::SetPollingMode() {
286 if (nfc_enabled && supported_features.nfc) { 287 if (nfc_enabled && supported_features.nfc) {
287 auto result = nfc_protocol->EnableNfc(); 288 auto result = nfc_protocol->EnableNfc();
288 if (result == DriverResult::Success) { 289 if (result == DriverResult::Success) {
289 result = nfc_protocol->StartNFCPollingMode();
290 }
291 if (result == DriverResult::Success) {
292 disable_input_thread = false;
293 return result; 290 return result;
294 } 291 }
295 nfc_protocol->DisableNfc(); 292 nfc_protocol->DisableNfc();
@@ -303,7 +300,6 @@ DriverResult JoyconDriver::SetPollingMode() {
303 } 300 }
304 if (result == DriverResult::Success) { 301 if (result == DriverResult::Success) {
305 ring_connected = true; 302 ring_connected = true;
306 disable_input_thread = false;
307 return result; 303 return result;
308 } 304 }
309 ring_connected = false; 305 ring_connected = false;
@@ -314,7 +310,6 @@ DriverResult JoyconDriver::SetPollingMode() {
314 if (passive_enabled && supported_features.passive) { 310 if (passive_enabled && supported_features.passive) {
315 const auto result = generic_protocol->EnablePassiveMode(); 311 const auto result = generic_protocol->EnablePassiveMode();
316 if (result == DriverResult::Success) { 312 if (result == DriverResult::Success) {
317 disable_input_thread = false;
318 return result; 313 return result;
319 } 314 }
320 LOG_ERROR(Input, "Error enabling passive mode"); 315 LOG_ERROR(Input, "Error enabling passive mode");
@@ -328,7 +323,6 @@ DriverResult JoyconDriver::SetPollingMode() {
328 // Switch calls this function after enabling active mode 323 // Switch calls this function after enabling active mode
329 generic_protocol->TriggersElapsed(); 324 generic_protocol->TriggersElapsed();
330 325
331 disable_input_thread = false;
332 return result; 326 return result;
333} 327}
334 328
@@ -492,9 +486,63 @@ DriverResult JoyconDriver::SetRingConMode() {
492 return result; 486 return result;
493} 487}
494 488
495DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { 489DriverResult JoyconDriver::StartNfcPolling() {
496 std::scoped_lock lock{mutex}; 490 std::scoped_lock lock{mutex};
491
492 if (!supported_features.nfc) {
493 return DriverResult::NotSupported;
494 }
495 if (!nfc_protocol->IsEnabled()) {
496 return DriverResult::Disabled;
497 }
498
499 disable_input_thread = true;
500 const auto result = nfc_protocol->StartNFCPollingMode();
501 disable_input_thread = false;
502
503 return result;
504}
505
506DriverResult JoyconDriver::StopNfcPolling() {
507 std::scoped_lock lock{mutex};
508
509 if (!supported_features.nfc) {
510 return DriverResult::NotSupported;
511 }
512 if (!nfc_protocol->IsEnabled()) {
513 return DriverResult::Disabled;
514 }
515
516 disable_input_thread = true;
517 const auto result = nfc_protocol->StopNFCPollingMode();
518 disable_input_thread = false;
519
520 return result;
521}
522
523DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
524 std::scoped_lock lock{mutex};
525
526 if (!supported_features.nfc) {
527 return DriverResult::NotSupported;
528 }
529 if (!nfc_protocol->IsEnabled()) {
530 return DriverResult::Disabled;
531 }
532 if (!amiibo_detected) {
533 return DriverResult::ErrorWritingData;
534 }
535
536 out_data.resize(0x21C);
497 disable_input_thread = true; 537 disable_input_thread = true;
538 const auto result = nfc_protocol->ReadAmiibo(out_data);
539 disable_input_thread = false;
540
541 return result;
542}
543
544DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
545 std::scoped_lock lock{mutex};
498 546
499 if (!supported_features.nfc) { 547 if (!supported_features.nfc) {
500 return DriverResult::NotSupported; 548 return DriverResult::NotSupported;
@@ -506,9 +554,51 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
506 return DriverResult::ErrorWritingData; 554 return DriverResult::ErrorWritingData;
507 } 555 }
508 556
557 disable_input_thread = true;
509 const auto result = nfc_protocol->WriteAmiibo(data); 558 const auto result = nfc_protocol->WriteAmiibo(data);
559 disable_input_thread = false;
510 560
561 return result;
562}
563
564DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
565 std::span<MifareReadData> out_data) {
566 std::scoped_lock lock{mutex};
567
568 if (!supported_features.nfc) {
569 return DriverResult::NotSupported;
570 }
571 if (!nfc_protocol->IsEnabled()) {
572 return DriverResult::Disabled;
573 }
574 if (!amiibo_detected) {
575 return DriverResult::ErrorWritingData;
576 }
577
578 disable_input_thread = true;
579 const auto result = nfc_protocol->ReadMifare(data, out_data);
580 disable_input_thread = false;
581
582 return result;
583}
584
585DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
586 std::scoped_lock lock{mutex};
587
588 if (!supported_features.nfc) {
589 return DriverResult::NotSupported;
590 }
591 if (!nfc_protocol->IsEnabled()) {
592 return DriverResult::Disabled;
593 }
594 if (!amiibo_detected) {
595 return DriverResult::ErrorWritingData;
596 }
597
598 disable_input_thread = true;
599 const auto result = nfc_protocol->WriteMifare(data);
511 disable_input_thread = false; 600 disable_input_thread = false;
601
512 return result; 602 return result;
513} 603}
514 604
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h
index e9b2fccbb..bc7025a21 100644
--- a/src/input_common/helpers/joycon_driver.h
+++ b/src/input_common/helpers/joycon_driver.h
@@ -49,7 +49,13 @@ public:
49 DriverResult SetIrMode(); 49 DriverResult SetIrMode();
50 DriverResult SetNfcMode(); 50 DriverResult SetNfcMode();
51 DriverResult SetRingConMode(); 51 DriverResult SetRingConMode();
52 DriverResult StartNfcPolling();
53 DriverResult StopNfcPolling();
54 DriverResult ReadAmiiboData(std::vector<u8>& out_data);
52 DriverResult WriteNfcData(std::span<const u8> data); 55 DriverResult WriteNfcData(std::span<const u8> data);
56 DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
57 std::span<MifareReadData> out_data);
58 DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
53 59
54 void SetCallbacks(const JoyconCallbacks& callbacks); 60 void SetCallbacks(const JoyconCallbacks& callbacks);
55 61
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index 5007b0e18..e0e431156 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 {
@@ -592,6 +606,14 @@ struct NFCWriteCommandData {
592static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); 606static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size");
593#pragma pack(pop) 607#pragma pack(pop)
594 608
609struct MifareCommandData {
610 u8 unknown1;
611 u8 unknown2;
612 u8 number_of_short_bytes;
613 MifareUUID uid;
614};
615static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size");
616
595struct NFCPollingCommandData { 617struct NFCPollingCommandData {
596 u8 enable_mifare; 618 u8 enable_mifare;
597 u8 unknown_1; 619 u8 unknown_1;
@@ -629,6 +651,41 @@ struct NFCWritePackage {
629 std::array<NFCDataChunk, 4> data_chunks; 651 std::array<NFCDataChunk, 4> data_chunks;
630}; 652};
631 653
654struct MifareReadChunk {
655 MifareCmd command;
656 std::array<u8, 0x6> sector_key;
657 u8 sector;
658};
659
660struct MifareWriteChunk {
661 MifareCmd command;
662 std::array<u8, 0x6> sector_key;
663 u8 sector;
664 std::array<u8, 0x10> data;
665};
666
667struct MifareReadData {
668 u8 sector;
669 std::array<u8, 0x10> data;
670};
671
672struct MifareReadPackage {
673 MifareCommandData command_data;
674 std::array<MifareReadChunk, 0x10> data_chunks;
675};
676
677struct MifareWritePackage {
678 MifareCommandData command_data;
679 std::array<MifareWriteChunk, 0x10> data_chunks;
680};
681
682struct TagInfo {
683 u8 uuid_length;
684 u8 protocol;
685 u8 tag_type;
686 std::array<u8, 10> uuid;
687};
688
632struct IrsConfigure { 689struct IrsConfigure {
633 MCUCommand command; 690 MCUCommand command;
634 MCUSubCommand sub_command; 691 MCUSubCommand sub_command;
@@ -744,7 +801,7 @@ struct JoyconCallbacks {
744 std::function<void(int, f32)> on_stick_data; 801 std::function<void(int, f32)> on_stick_data;
745 std::function<void(int, const MotionData&)> on_motion_data; 802 std::function<void(int, const MotionData&)> on_motion_data;
746 std::function<void(f32)> on_ring_data; 803 std::function<void(f32)> on_ring_data;
747 std::function<void(const std::vector<u8>&)> on_amiibo_data; 804 std::function<void(const Joycon::TagInfo&)> on_amiibo_data;
748 std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; 805 std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data;
749}; 806};
750 807
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp
index f7058c4a7..261f46255 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -40,6 +40,16 @@ DriverResult NfcProtocol::EnableNfc() {
40 if (result == DriverResult::Success) { 40 if (result == DriverResult::Success) {
41 result = WaitUntilNfcIs(NFCStatus::Ready); 41 result = WaitUntilNfcIs(NFCStatus::Ready);
42 } 42 }
43 if (result == DriverResult::Success) {
44 MCUCommandResponse output{};
45 result = SendStopPollingRequest(output);
46 }
47 if (result == DriverResult::Success) {
48 result = WaitUntilNfcIs(NFCStatus::Ready);
49 }
50 if (result == DriverResult::Success) {
51 is_enabled = true;
52 }
43 53
44 return result; 54 return result;
45} 55}
@@ -54,37 +64,50 @@ DriverResult NfcProtocol::DisableNfc() {
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() { 72DriverResult 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 DriverResult result{DriverResult::Success};
65 76
66 if (result == DriverResult::Success) { 77 if (result == 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 == DriverResult::Success) {
71 result = WaitUntilNfcIs(NFCStatus::Ready); 82 result = WaitUntilNfcIs(NFCStatus::Polling);
72 } 83 }
73 if (result == DriverResult::Success) { 84 if (result == DriverResult::Success) {
85 is_polling = true;
86 }
87
88 return result;
89}
90
91DriverResult NfcProtocol::StopNFCPollingMode() {
92 LOG_DEBUG(Input, "Stop NFC polling Mode");
93 ScopedSetBlocking sb(this);
94 DriverResult result{DriverResult::Success};
95
96 if (result == 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 == DriverResult::Success) {
78 result = WaitUntilNfcIs(NFCStatus::Polling); 101 result = WaitUntilNfcIs(NFCStatus::WriteReady);
79 } 102 }
80 if (result == DriverResult::Success) { 103 if (result == 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) { 110DriverResult 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 DriverResult::Delayed;
90 } 113 }
@@ -100,11 +123,41 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) {
100 } 123 }
101 124
102 if (result == DriverResult::Success) { 125 if (result == 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
150DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
151 LOG_DEBUG(Input, "Scan for amiibos");
152 ScopedSetBlocking sb(this);
153 DriverResult result{DriverResult::Success};
154 TagFoundData tag_data{};
155
156 if (result == DriverResult::Success) {
157 result = IsTagInRange(tag_data, 7);
158 }
159
160 if (result == DriverResult::Success) {
108 result = GetAmiiboData(data); 161 result = GetAmiiboData(data);
109 } 162 }
110 163
@@ -154,6 +207,69 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
154 return result; 207 return result;
155} 208}
156 209
210DriverResult 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 DriverResult result{DriverResult::Success};
215 TagFoundData tag_data{};
216 MifareUUID tag_uuid{};
217
218 if (result == DriverResult::Success) {
219 result = IsTagInRange(tag_data, 7);
220 }
221 if (result == 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 == DriverResult::Success) {
226 MCUCommandResponse output{};
227 result = SendStopPollingRequest(output);
228 }
229 if (result == DriverResult::Success) {
230 result = WaitUntilNfcIs(NFCStatus::Ready);
231 }
232 if (result == DriverResult::Success) {
233 MCUCommandResponse output{};
234 result = SendStartPollingRequest(output, true);
235 }
236 if (result == DriverResult::Success) {
237 result = WaitUntilNfcIs(NFCStatus::WriteReady);
238 }
239 return result;
240}
241
242DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) {
243 LOG_DEBUG(Input, "Write mifare");
244 ScopedSetBlocking sb(this);
245 DriverResult result{DriverResult::Success};
246 TagFoundData tag_data{};
247 MifareUUID tag_uuid{};
248
249 if (result == DriverResult::Success) {
250 result = IsTagInRange(tag_data, 7);
251 }
252 if (result == DriverResult::Success) {
253 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
254 result = WriteMifareData(tag_uuid, write_request);
255 }
256 if (result == DriverResult::Success) {
257 MCUCommandResponse output{};
258 result = SendStopPollingRequest(output);
259 }
260 if (result == DriverResult::Success) {
261 result = WaitUntilNfcIs(NFCStatus::Ready);
262 }
263 if (result == DriverResult::Success) {
264 MCUCommandResponse output{};
265 result = SendStartPollingRequest(output, true);
266 }
267 if (result == DriverResult::Success) {
268 result = WaitUntilNfcIs(NFCStatus::WriteReady);
269 }
270 return result;
271}
272
157bool NfcProtocol::HasAmiibo() { 273bool NfcProtocol::HasAmiibo() {
158 if (update_counter++ < AMIIBO_UPDATE_DELAY) { 274 if (update_counter++ < AMIIBO_UPDATE_DELAY) {
159 return true; 275 return true;
@@ -341,6 +457,158 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
341 return result; 457 return result;
342} 458}
343 459
460DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
461 std::span<const MifareReadChunk> read_request,
462 std::span<MifareReadData> out_data) {
463 constexpr std::size_t timeout_limit = 60;
464 const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request);
465 const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data);
466 std::span<const u8> buffer(nfc_buffer_data);
467 DriverResult result = DriverResult::Success;
468 MCUCommandResponse output{};
469 u8 block_id = 1;
470 u8 package_index = 0;
471 std::size_t tries = 0;
472 std::size_t current_position = 0;
473
474 LOG_INFO(Input, "Reading Mifare data");
475
476 // Send data request. Nfc buffer size is 31, Send the data in smaller packages
477 while (current_position < buffer.size() && tries++ < timeout_limit) {
478 const std::size_t next_position =
479 std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size());
480 const std::size_t block_size = next_position - current_position;
481 const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data);
482
483 SendReadDataMifareRequest(output, block_id, is_last_packet,
484 buffer.subspan(current_position, block_size));
485
486 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
487
488 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
489 return DriverResult::ErrorReadingData;
490 }
491
492 // Increase position when data is confirmed by the joycon
493 if (output.mcu_report == MCUReport::NFCState &&
494 (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 &&
495 output.mcu_data[3] == block_id) {
496 block_id++;
497 current_position = next_position;
498 }
499 }
500
501 if (result != DriverResult::Success) {
502 return result;
503 }
504
505 // Wait for reply and save the output data
506 while (tries++ < timeout_limit) {
507 result = SendNextPackageRequest(output, package_index);
508 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
509
510 if (result != DriverResult::Success) {
511 return result;
512 }
513
514 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
515 return DriverResult::ErrorReadingData;
516 }
517
518 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
519 constexpr std::size_t DATA_LENGHT = 0x10 + 1;
520 constexpr std::size_t DATA_START = 11;
521 const u8 number_of_elements = output.mcu_data[10];
522 for (std::size_t i = 0; i < number_of_elements; i++) {
523 out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)];
524 memcpy(out_data[i].data.data(),
525 output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT),
526 sizeof(MifareReadData::data));
527 }
528 package_index++;
529 continue;
530 }
531
532 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) {
533 LOG_INFO(Input, "Finished reading mifare");
534 break;
535 }
536 }
537
538 return result;
539}
540
541DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
542 std::span<const MifareWriteChunk> write_request) {
543 constexpr std::size_t timeout_limit = 60;
544 const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request);
545 const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data);
546 std::span<const u8> buffer(nfc_buffer_data);
547 DriverResult result = DriverResult::Success;
548 MCUCommandResponse output{};
549 u8 block_id = 1;
550 u8 package_index = 0;
551 std::size_t tries = 0;
552 std::size_t current_position = 0;
553
554 LOG_INFO(Input, "Writing Mifare data");
555
556 // Send data request. Nfc buffer size is 31, Send the data in smaller packages
557 while (current_position < buffer.size() && tries++ < timeout_limit) {
558 const std::size_t next_position =
559 std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size());
560 const std::size_t block_size = next_position - current_position;
561 const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data);
562
563 SendReadDataMifareRequest(output, block_id, is_last_packet,
564 buffer.subspan(current_position, block_size));
565
566 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
567
568 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
569 return DriverResult::ErrorReadingData;
570 }
571
572 // Increase position when data is confirmed by the joycon
573 if (output.mcu_report == MCUReport::NFCState &&
574 (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 &&
575 output.mcu_data[3] == block_id) {
576 block_id++;
577 current_position = next_position;
578 }
579 }
580
581 if (result != DriverResult::Success) {
582 return result;
583 }
584
585 // Wait for reply and ignore the output data
586 while (tries++ < timeout_limit) {
587 result = SendNextPackageRequest(output, package_index);
588 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
589
590 if (result != DriverResult::Success) {
591 return result;
592 }
593
594 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
595 return DriverResult::ErrorReadingData;
596 }
597
598 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
599 package_index++;
600 continue;
601 }
602
603 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) {
604 LOG_INFO(Input, "Finished writing mifare");
605 break;
606 }
607 }
608
609 return result;
610}
611
344DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, 612DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
345 bool is_second_attempt) { 613 bool is_second_attempt) {
346 NFCRequestState request{ 614 NFCRequestState request{
@@ -477,6 +745,28 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
477 output); 745 output);
478} 746}
479 747
748DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
749 bool is_last_packet, std::span<const u8> data) {
750 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
751 NFCRequestState request{
752 .command_argument = NFCCommand::Mifare,
753 .block_id = block_id,
754 .packet_id = {},
755 .packet_flag =
756 is_last_packet ? MCUPacketFlag::LastCommandPacket : MCUPacketFlag::MorePacketsRemaining,
757 .data_length = static_cast<u8>(data_size),
758 .raw_data = {},
759 .crc = {},
760 };
761 memcpy(request.raw_data.data(), data.data(), data_size);
762
763 std::array<u8, sizeof(NFCRequestState)> request_data{};
764 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
765 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
766 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
767 output);
768}
769
480std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { 770std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const {
481 const std::size_t header_size = 771 const std::size_t header_size =
482 sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); 772 sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks);
@@ -498,6 +788,48 @@ std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& packag
498 return serialized_data; 788 return serialized_data;
499} 789}
500 790
791std::vector<u8> NfcProtocol::SerializeMifareReadPackage(const MifareReadPackage& package) const {
792 const std::size_t header_size = sizeof(MifareCommandData);
793 std::vector<u8> serialized_data(header_size);
794 std::size_t start_index = 0;
795
796 memcpy(serialized_data.data(), &package, header_size);
797 start_index += header_size;
798
799 for (const auto& data_chunk : package.data_chunks) {
800 const std::size_t chunk_size = sizeof(MifareReadChunk);
801 if (data_chunk.command == MifareCmd::None) {
802 continue;
803 }
804 serialized_data.resize(start_index + chunk_size);
805 memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size);
806 start_index += chunk_size;
807 }
808
809 return serialized_data;
810}
811
812std::vector<u8> NfcProtocol::SerializeMifareWritePackage(const MifareWritePackage& package) const {
813 const std::size_t header_size = sizeof(MifareCommandData);
814 std::vector<u8> serialized_data(header_size);
815 std::size_t start_index = 0;
816
817 memcpy(serialized_data.data(), &package, header_size);
818 start_index += header_size;
819
820 for (const auto& data_chunk : package.data_chunks) {
821 const std::size_t chunk_size = sizeof(MifareWriteChunk);
822 if (data_chunk.command == MifareCmd::None) {
823 continue;
824 }
825 serialized_data.resize(start_index + chunk_size);
826 memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size);
827 start_index += chunk_size;
828 }
829
830 return serialized_data;
831}
832
501NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, 833NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid,
502 std::span<const u8> data) const { 834 std::span<const u8> data) const {
503 return { 835 return {
@@ -527,6 +859,46 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid,
527 }; 859 };
528} 860}
529 861
862MifareReadPackage NfcProtocol::MakeMifareReadPackage(
863 const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request) const {
864 MifareReadPackage package{
865 .command_data{
866 .unknown1 = 0xd0,
867 .unknown2 = 0x07,
868 .number_of_short_bytes = static_cast<u8>(
869 ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID)) / 2),
870 .uid = tag_uuid,
871 },
872 .data_chunks = {},
873 };
874
875 for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) {
876 package.data_chunks[i] = read_request[i];
877 }
878
879 return package;
880}
881
882MifareWritePackage NfcProtocol::MakeMifareWritePackage(
883 const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> read_request) const {
884 MifareWritePackage package{
885 .command_data{
886 .unknown1 = 0xd0,
887 .unknown2 = 0x07,
888 .number_of_short_bytes = static_cast<u8>(
889 ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID) + 2) / 2),
890 .uid = tag_uuid,
891 },
892 .data_chunks = {},
893 };
894
895 for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) {
896 package.data_chunks[i] = read_request[i];
897 }
898
899 return package;
900}
901
530NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { 902NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const {
531 constexpr u8 NFC_PAGE_SIZE = 4; 903 constexpr u8 NFC_PAGE_SIZE = 4;
532 904
@@ -606,4 +978,8 @@ bool NfcProtocol::IsEnabled() const {
606 return is_enabled; 978 return is_enabled;
607} 979}
608 980
981bool NfcProtocol::IsPolling() const {
982 return is_polling;
983}
984
609} // namespace InputCommon::Joycon 985} // 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..0be95e40e 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.h
+++ b/src/input_common/helpers/joycon_protocol/nfc.h
@@ -25,14 +25,25 @@ public:
25 25
26 DriverResult StartNFCPollingMode(); 26 DriverResult StartNFCPollingMode();
27 27
28 DriverResult ScanAmiibo(std::vector<u8>& data); 28 DriverResult StopNFCPollingMode();
29
30 DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
31
32 DriverResult ReadAmiibo(std::vector<u8>& data);
29 33
30 DriverResult WriteAmiibo(std::span<const u8> data); 34 DriverResult WriteAmiibo(std::span<const u8> data);
31 35
36 DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
37 std::span<MifareReadData> out_data);
38
39 DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
40
32 bool HasAmiibo(); 41 bool HasAmiibo();
33 42
34 bool IsEnabled() const; 43 bool IsEnabled() const;
35 44
45 bool IsPolling() const;
46
36private: 47private:
37 // Number of times the function will be delayed until it outputs valid data 48 // Number of times the function will be delayed until it outputs valid data
38 static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; 49 static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15;
@@ -51,6 +62,13 @@ private:
51 62
52 DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); 63 DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
53 64
65 DriverResult GetMifareData(const MifareUUID& tag_uuid,
66 std::span<const MifareReadChunk> read_request,
67 std::span<MifareReadData> out_data);
68
69 DriverResult WriteMifareData(const MifareUUID& tag_uuid,
70 std::span<const MifareWriteChunk> write_request);
71
54 DriverResult SendStartPollingRequest(MCUCommandResponse& output, 72 DriverResult SendStartPollingRequest(MCUCommandResponse& output,
55 bool is_second_attempt = false); 73 bool is_second_attempt = false);
56 74
@@ -65,17 +83,31 @@ private:
65 DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, 83 DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
66 bool is_last_packet, std::span<const u8> data); 84 bool is_last_packet, std::span<const u8> data);
67 85
86 DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
87 bool is_last_packet, std::span<const u8> data);
88
68 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; 89 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const;
69 90
91 std::vector<u8> SerializeMifareReadPackage(const MifareReadPackage& package) const;
92
93 std::vector<u8> SerializeMifareWritePackage(const MifareWritePackage& package) const;
94
70 NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; 95 NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const;
71 96
72 NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; 97 NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const;
73 98
99 MifareReadPackage MakeMifareReadPackage(const MifareUUID& tag_uuid,
100 std::span<const MifareReadChunk> read_request) const;
101
102 MifareWritePackage MakeMifareWritePackage(const MifareUUID& tag_uuid,
103 std::span<const MifareWriteChunk> read_request) const;
104
74 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; 105 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const;
75 106
76 TagUUID GetTagUUID(std::span<const u8> data) const; 107 TagUUID GetTagUUID(std::span<const u8> data) const;
77 108
78 bool is_enabled{}; 109 bool is_enabled{};
110 bool is_polling{};
79 std::size_t update_counter{}; 111 std::size_t update_counter{};
80}; 112};
81 113
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,