summaryrefslogtreecommitdiff
path: root/src/input_common/helpers/joycon_protocol/nfc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/helpers/joycon_protocol/nfc.cpp')
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp531
1 files changed, 457 insertions, 74 deletions
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