diff options
Diffstat (limited to 'src/input_common/helpers/joycon_protocol')
6 files changed, 481 insertions, 18 deletions
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 51669261a..88f4cec1c 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp | |||
| @@ -73,7 +73,7 @@ DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { | |||
| 73 | DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, | 73 | DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, |
| 74 | SubCommandResponse& output) { | 74 | SubCommandResponse& output) { |
| 75 | constexpr int timeout_mili = 66; | 75 | constexpr int timeout_mili = 66; |
| 76 | constexpr int MaxTries = 15; | 76 | constexpr int MaxTries = 3; |
| 77 | int tries = 0; | 77 | int tries = 0; |
| 78 | 78 | ||
| 79 | do { | 79 | do { |
| @@ -113,9 +113,7 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const | |||
| 113 | return result; | 113 | return result; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | result = GetSubCommandResponse(sc, output); | 116 | return GetSubCommandResponse(sc, output); |
| 117 | |||
| 118 | return DriverResult::Success; | ||
| 119 | } | 117 | } |
| 120 | 118 | ||
| 121 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { | 119 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { |
| @@ -158,7 +156,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe | |||
| 158 | 156 | ||
| 159 | DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { | 157 | DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { |
| 160 | constexpr std::size_t HeaderSize = 5; | 158 | constexpr std::size_t HeaderSize = 5; |
| 161 | constexpr std::size_t MaxTries = 10; | 159 | constexpr std::size_t MaxTries = 5; |
| 162 | std::size_t tries = 0; | 160 | std::size_t tries = 0; |
| 163 | SubCommandResponse response{}; | 161 | SubCommandResponse response{}; |
| 164 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; | 162 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; |
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 | |||
| 24 | using MacAddress = std::array<u8, 6>; | 24 | using MacAddress = std::array<u8, 6>; |
| 25 | using SerialNumber = std::array<u8, 15>; | 25 | using SerialNumber = std::array<u8, 15>; |
| 26 | using TagUUID = std::array<u8, 7>; | 26 | using TagUUID = std::array<u8, 7>; |
| 27 | using MifareUUID = std::array<u8, 4>; | ||
| 27 | 28 | ||
| 28 | enum class ControllerType : u8 { | 29 | enum 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 | |||
| 314 | enum 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 | ||
| 312 | enum class IrsMode : u8 { | 326 | enum class IrsMode : u8 { |
| @@ -592,6 +606,14 @@ struct NFCWriteCommandData { | |||
| 592 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); | 606 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); |
| 593 | #pragma pack(pop) | 607 | #pragma pack(pop) |
| 594 | 608 | ||
| 609 | struct MifareCommandData { | ||
| 610 | u8 unknown1; | ||
| 611 | u8 unknown2; | ||
| 612 | u8 number_of_short_bytes; | ||
| 613 | MifareUUID uid; | ||
| 614 | }; | ||
| 615 | static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size"); | ||
| 616 | |||
| 595 | struct NFCPollingCommandData { | 617 | struct 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 | ||
| 654 | struct MifareReadChunk { | ||
| 655 | MifareCmd command; | ||
| 656 | std::array<u8, 0x6> sector_key; | ||
| 657 | u8 sector; | ||
| 658 | }; | ||
| 659 | |||
| 660 | struct MifareWriteChunk { | ||
| 661 | MifareCmd command; | ||
| 662 | std::array<u8, 0x6> sector_key; | ||
| 663 | u8 sector; | ||
| 664 | std::array<u8, 0x10> data; | ||
| 665 | }; | ||
| 666 | |||
| 667 | struct MifareReadData { | ||
| 668 | u8 sector; | ||
| 669 | std::array<u8, 0x10> data; | ||
| 670 | }; | ||
| 671 | |||
| 672 | struct MifareReadPackage { | ||
| 673 | MifareCommandData command_data; | ||
| 674 | std::array<MifareReadChunk, 0x10> data_chunks; | ||
| 675 | }; | ||
| 676 | |||
| 677 | struct MifareWritePackage { | ||
| 678 | MifareCommandData command_data; | ||
| 679 | std::array<MifareWriteChunk, 0x10> data_chunks; | ||
| 680 | }; | ||
| 681 | |||
| 682 | struct TagInfo { | ||
| 683 | u8 uuid_length; | ||
| 684 | u8 protocol; | ||
| 685 | u8 tag_type; | ||
| 686 | std::array<u8, 10> uuid; | ||
| 687 | }; | ||
| 688 | |||
| 632 | struct IrsConfigure { | 689 | struct 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 | ||
| 61 | DriverResult NfcProtocol::StartNFCPollingMode() { | 72 | 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 | 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 | |||
| 91 | DriverResult 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 | ||
| 87 | DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { | 110 | 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 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 | |||
| 150 | DriverResult 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 | ||
| 210 | 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 | 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 | |||
| 242 | DriverResult 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 | |||
| 157 | bool NfcProtocol::HasAmiibo() { | 273 | bool 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 | ||
| 460 | DriverResult 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 | |||
| 541 | DriverResult 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 | |||
| 344 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, | 612 | DriverResult 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 | ||
| 748 | DriverResult 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 | |||
| 480 | std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { | 770 | std::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 | ||
| 791 | std::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 | |||
| 812 | std::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 | |||
| 501 | NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, | 833 | NFCWritePackage 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 | ||
| 862 | MifareReadPackage 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 | |||
| 882 | MifareWritePackage 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 | |||
| 530 | NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { | 902 | NFCDataChunk 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 | ||
| 981 | bool 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 | |||
| 36 | private: | 47 | private: |
| 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 | ||
| 73 | void JoyconPoller::UpdateAmiibo(const std::vector<u8>& amiibo_data) { | 73 | void 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 | ||
| 77 | void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) { | 77 | void 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 | ||
| 42 | private: | 42 | private: |
| 43 | void UpdateActiveLeftPadInput(const InputReportActive& input, | 43 | void UpdateActiveLeftPadInput(const InputReportActive& input, |