diff options
author | Narr the Reg <juangerman-13@hotmail.com> | 2023-06-17 05:57:21 +0200 |
---|---|---|
committer | Narr the Reg <juangerman-13@hotmail.com> | 2023-06-22 01:54:58 +0200 |
commit | 84d43489c5df9f450efb0293cc58161d08e3b882 (patch) | |
tree | c4d45b021c78392956dc58d409a34632fe135d2b /src/input_common | |
parent | Merge pull request #10783 from liamwhite/memory (diff) | |
download | yuzu-84d43489c5df9f450efb0293cc58161d08e3b882.tar yuzu-84d43489c5df9f450efb0293cc58161d08e3b882.tar.gz yuzu-84d43489c5df9f450efb0293cc58161d08e3b882.tar.bz2 yuzu-84d43489c5df9f450efb0293cc58161d08e3b882.tar.lz yuzu-84d43489c5df9f450efb0293cc58161d08e3b882.tar.xz yuzu-84d43489c5df9f450efb0293cc58161d08e3b882.tar.zst yuzu-84d43489c5df9f450efb0293cc58161d08e3b882.zip |
Diffstat (limited to 'src/input_common')
-rw-r--r-- | src/input_common/drivers/joycon.cpp | 133 | ||||
-rw-r--r-- | src/input_common/drivers/joycon.h | 18 | ||||
-rw-r--r-- | src/input_common/drivers/virtual_amiibo.cpp | 130 | ||||
-rw-r--r-- | src/input_common/drivers/virtual_amiibo.h | 16 | ||||
-rw-r--r-- | src/input_common/helpers/joycon_driver.cpp | 118 | ||||
-rw-r--r-- | src/input_common/helpers/joycon_driver.h | 6 | ||||
-rw-r--r-- | src/input_common/helpers/joycon_protocol/joycon_types.h | 59 | ||||
-rw-r--r-- | src/input_common/helpers/joycon_protocol/nfc.cpp | 390 | ||||
-rw-r--r-- | src/input_common/helpers/joycon_protocol/nfc.h | 34 | ||||
-rw-r--r-- | src/input_common/helpers/joycon_protocol/poller.cpp | 4 | ||||
-rw-r--r-- | src/input_common/helpers/joycon_protocol/poller.h | 4 | ||||
-rw-r--r-- | src/input_common/input_engine.h | 34 | ||||
-rw-r--r-- | src/input_common/input_poller.cpp | 24 |
13 files changed, 915 insertions, 55 deletions
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index b2b5677c8..52494e0d9 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { OnMotionUpdate(port, type, id, value); }}, .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, - .on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) { - OnAmiiboUpdate(port, type, amiibo_data); + .on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) { + OnAmiiboUpdate(port, type, tag_info); }}, .on_camera_data = {[this, port](const std::vector<u8>& camera_data, Joycon::IrsResolution format) { @@ -291,13 +291,105 @@ Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) c return Common::Input::NfcState::Success; }; +Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->StartNfcPolling()); +}; + +Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->StopNfcPolling()); +}; + +Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier, + std::vector<u8>& out_data) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->ReadAmiiboData(out_data)); +} + Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, const std::vector<u8>& data) { auto handle = GetHandle(identifier); - if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { - return Common::Input::NfcState::WriteFailed; + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; } - return Common::Input::NfcState::Success; + return TranslateDriverResult(handle->WriteNfcData(data)); +}; + +Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& data) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + + const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); + std::vector<Joycon::MifareReadChunk> read_request{}; + for (const auto& request_data : request.data) { + if (request_data.command == 0) { + continue; + } + Joycon::MifareReadChunk chunk = { + .command = command, + .sector_key = {}, + .sector = request_data.sector, + }; + memcpy(chunk.sector_key.data(), request_data.key.data(), + sizeof(Joycon::MifareReadChunk::sector_key)); + read_request.emplace_back(chunk); + } + + std::vector<Joycon::MifareReadData> read_data(read_request.size()); + const auto result = handle->ReadMifareData(read_request, read_data); + if (result == Joycon::DriverResult::Success) { + for (std::size_t i = 0; i < read_request.size(); i++) { + data.data[i] = { + .command = static_cast<u8>(command), + .sector = read_data[i].sector, + .key = {}, + .data = read_data[i].data, + }; + } + } + return TranslateDriverResult(result); +}; + +Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + + const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); + std::vector<Joycon::MifareWriteChunk> write_request{}; + for (const auto& request_data : request.data) { + if (request_data.command == 0) { + continue; + } + Joycon::MifareWriteChunk chunk = { + .command = command, + .sector_key = {}, + .sector = request_data.sector, + .data = {}, + }; + memcpy(chunk.sector_key.data(), request_data.key.data(), + sizeof(Joycon::MifareReadChunk::sector_key)); + memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data)); + write_request.emplace_back(chunk); + } + + return TranslateDriverResult(handle->WriteMifareData(write_request)); }; Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, @@ -403,11 +495,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) { } void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, - const std::vector<u8>& amiibo_data) { + const Joycon::TagInfo& tag_info) { const auto identifier = GetIdentifier(port, type); - const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved - : Common::Input::NfcState::NewAmiibo; - SetNfc(identifier, {nfc_state, amiibo_data}); + const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved + : Common::Input::NfcState::NewAmiibo; + + const Common::Input::NfcStatus nfc_status{ + .state = nfc_state, + .uuid_length = tag_info.uuid_length, + .protocol = tag_info.protocol, + .tag_type = tag_info.tag_type, + .uuid = tag_info.uuid, + }; + + SetNfc(identifier, nfc_status); } void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, @@ -726,4 +827,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { return "Unknown Switch Controller"; } } + +Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { + switch (result) { + case Joycon::DriverResult::Success: + return Common::Input::NfcState::Success; + case Joycon::DriverResult::Disabled: + return Common::Input::NfcState::WrongDeviceState; + case Joycon::DriverResult::NotSupported: + return Common::Input::NfcState::NotSupported; + default: + return Common::Input::NfcState::Unknown; + } +} + } // namespace InputCommon diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index e3f0ad78f..4c323d7d6 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -15,6 +15,7 @@ using SerialNumber = std::array<u8, 15>; struct Battery; struct Color; struct MotionData; +struct TagInfo; enum class ControllerType : u8; enum class DriverResult; enum class IrsResolution; @@ -39,9 +40,18 @@ public: Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, Common::Input::CameraFormat camera_format) override; - Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; - Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, + Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override; + Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override; + Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override; + Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier, + std::vector<u8>& out_data) override; + Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier, const std::vector<u8>& data) override; + Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) override; + Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request) override; Common::Input::DriverResult SetPollingMode( const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; @@ -82,7 +92,7 @@ private: const Joycon::MotionData& value); void OnRingConUpdate(f32 ring_data); void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, - const std::vector<u8>& amiibo_data); + const Joycon::TagInfo& amiibo_data); void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, Joycon::IrsResolution format); @@ -102,6 +112,8 @@ private: /// Returns the name of the device in text format std::string JoyconName(Joycon::ControllerType type) const; + Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; + std::jthread scan_thread; // Joycon types are split by type to ease supporting dualjoycon configurations diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 6435b8af8..180eb53ef 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode( switch (polling_mode) { case Common::Input::PollingMode::NFC: - if (state == State::Initialized) { - state = State::WaitingForAmiibo; - } + state = State::Initialized; return Common::Input::DriverResult::Success; default: - if (state == State::AmiiboIsOpen) { + if (state == State::TagNearby) { CloseAmiibo(); } + state = State::Disabled; return Common::Input::DriverResult::NotSupported; } } @@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc( [[maybe_unused]] const PadIdentifier& identifier_) const { return Common::Input::NfcState::Success; } +Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) { + if (state != State::Initialized) { + return Common::Input::NfcState::WrongDeviceState; + } + state = State::WaitingForAmiibo; + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) { + if (state == State::Disabled) { + return Common::Input::NfcState::WrongDeviceState; + } + if (state == State::TagNearby) { + CloseAmiibo(); + } + state = State::Initialized; + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_, + std::vector<u8>& out_data) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 1) { + return Common::Input::NfcState::InvalidTagType; + } + + out_data.resize(nfc_data.size()); + memcpy(out_data.data(), nfc_data.data(), nfc_data.size()); + return Common::Input::NfcState::Success; +} Common::Input::NfcState VirtualAmiibo::WriteNfcData( [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { @@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( return Common::Input::NfcState::Success; } +Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 6) { + return Common::Input::NfcState::InvalidTagType; + } + + for (std::size_t i = 0; i < request.data.size(); i++) { + if (request.data[i].command == 0) { + continue; + } + out_data.data[i].command = request.data[i].command; + out_data.data[i].sector = request.data[i].sector; + + const std::size_t sector_index = + request.data[i].sector * sizeof(Common::Input::MifareData::data); + + if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { + return Common::Input::NfcState::WriteFailed; + } + + // Ignore the sector key as we don't support it + memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index, + sizeof(Common::Input::MifareData::data)); + } + + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::WriteMifareData( + const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 6) { + return Common::Input::NfcState::InvalidTagType; + } + + for (std::size_t i = 0; i < request.data.size(); i++) { + if (request.data[i].command == 0) { + continue; + } + + const std::size_t sector_index = + request.data[i].sector * sizeof(Common::Input::MifareData::data); + + if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { + return Common::Input::NfcState::WriteFailed; + } + + // Ignore the sector key as we don't support it + memcpy(nfc_data.data() + sector_index, request.data[i].data.data(), + sizeof(Common::Input::MifareData::data)); + } + + return Common::Input::NfcState::Success; +} + VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { return state; } @@ -112,23 +207,31 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) { case AmiiboSizeWithoutPassword: case AmiiboSizeWithSignature: nfc_data.resize(AmiiboSize); + status.tag_type = 1U << 1; + status.uuid_length = 7; break; case MifareSize: nfc_data.resize(MifareSize); + status.tag_type = 1U << 6; + status.uuid_length = 4; break; default: return Info::NotAnAmiibo; } - state = State::AmiiboIsOpen; + status.uuid = {}; + status.protocol = 1; + state = State::TagNearby; + status.state = Common::Input::NfcState::NewAmiibo, memcpy(nfc_data.data(), data.data(), data.size_bytes()); - SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); + memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length); + SetNfc(identifier, status); return Info::Success; } VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { - if (state == State::AmiiboIsOpen) { - SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); + if (state == State::TagNearby) { + SetNfc(identifier, status); return Info::Success; } @@ -136,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { } VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { - state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo - : State::Initialized; - SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}}); + if (state != State::TagNearby) { + return Info::Success; + } + + state = State::WaitingForAmiibo; + status.state = Common::Input::NfcState::AmiiboRemoved; + SetNfc(identifier, status); + status.tag_type = 0; return Info::Success; } diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 09ca09e68..490f38e05 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -20,9 +20,10 @@ namespace InputCommon { class VirtualAmiibo final : public InputEngine { public: enum class State { + Disabled, Initialized, WaitingForAmiibo, - AmiiboIsOpen, + TagNearby, }; enum class Info { @@ -41,9 +42,17 @@ public: const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; - + Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override; + Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override; + Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_, + std::vector<u8>& out_data) override; Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, const std::vector<u8>& data) override; + Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& data, + Common::Input::MifareRequest& out_data) override; + Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& data) override; State GetCurrentState() const; @@ -61,8 +70,9 @@ private: static constexpr std::size_t MifareSize = 0x400; std::string file_path{}; - State state{State::Initialized}; + State state{State::Disabled}; std::vector<u8> nfc_data; + Common::Input::NfcStatus status; Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; }; } // namespace InputCommon 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 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" +#include "common/scope_exit.h" #include "common/swap.h" #include "common/thread.h" #include "input_common/helpers/joycon_driver.h" @@ -112,7 +113,7 @@ DriverResult JoyconDriver::InitializeDevice() { joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, right_stick_calibration, motion_calibration); - // Start pooling for data + // Start polling for data is_connected = true; if (!input_thread_running) { input_thread = @@ -208,7 +209,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); } - if (nfc_protocol->IsEnabled()) { + if (nfc_protocol->IsPolling()) { if (amiibo_detected) { if (!nfc_protocol->HasAmiibo()) { joycon_poller->UpdateAmiibo({}); @@ -218,10 +219,10 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { } if (!amiibo_detected) { - std::vector<u8> data(0x21C); - const auto result = nfc_protocol->ScanAmiibo(data); + Joycon::TagInfo tag_info; + const auto result = nfc_protocol->GetTagInfo(tag_info); if (result == DriverResult::Success) { - joycon_poller->UpdateAmiibo(data); + joycon_poller->UpdateAmiibo(tag_info); amiibo_detected = true; } } @@ -247,6 +248,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { } DriverResult JoyconDriver::SetPollingMode() { + SCOPE_EXIT({ disable_input_thread = false; }); disable_input_thread = true; rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); @@ -276,7 +278,6 @@ DriverResult JoyconDriver::SetPollingMode() { if (irs_enabled && supported_features.irs) { auto result = irs_protocol->EnableIrs(); if (result == DriverResult::Success) { - disable_input_thread = false; return result; } irs_protocol->DisableIrs(); @@ -286,10 +287,6 @@ DriverResult JoyconDriver::SetPollingMode() { if (nfc_enabled && supported_features.nfc) { auto result = nfc_protocol->EnableNfc(); if (result == DriverResult::Success) { - result = nfc_protocol->StartNFCPollingMode(); - } - if (result == DriverResult::Success) { - disable_input_thread = false; return result; } nfc_protocol->DisableNfc(); @@ -303,7 +300,6 @@ DriverResult JoyconDriver::SetPollingMode() { } if (result == DriverResult::Success) { ring_connected = true; - disable_input_thread = false; return result; } ring_connected = false; @@ -314,7 +310,6 @@ DriverResult JoyconDriver::SetPollingMode() { if (passive_enabled && supported_features.passive) { const auto result = generic_protocol->EnablePassiveMode(); if (result == DriverResult::Success) { - disable_input_thread = false; return result; } LOG_ERROR(Input, "Error enabling passive mode"); @@ -328,7 +323,6 @@ DriverResult JoyconDriver::SetPollingMode() { // Switch calls this function after enabling active mode generic_protocol->TriggersElapsed(); - disable_input_thread = false; return result; } @@ -492,9 +486,63 @@ DriverResult JoyconDriver::SetRingConMode() { return result; } -DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { +DriverResult JoyconDriver::StartNfcPolling() { std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + + disable_input_thread = true; + const auto result = nfc_protocol->StartNFCPollingMode(); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::StopNfcPolling() { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + + disable_input_thread = true; + const auto result = nfc_protocol->StopNFCPollingMode(); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + if (!amiibo_detected) { + return DriverResult::ErrorWritingData; + } + + out_data.resize(0x21C); disable_input_thread = true; + const auto result = nfc_protocol->ReadAmiibo(out_data); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { + std::scoped_lock lock{mutex}; if (!supported_features.nfc) { return DriverResult::NotSupported; @@ -506,9 +554,51 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { return DriverResult::ErrorWritingData; } + disable_input_thread = true; const auto result = nfc_protocol->WriteAmiibo(data); + disable_input_thread = false; + return result; +} + +DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data, + std::span<MifareReadData> out_data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + if (!amiibo_detected) { + return DriverResult::ErrorWritingData; + } + + disable_input_thread = true; + const auto result = nfc_protocol->ReadMifare(data, out_data); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + if (!amiibo_detected) { + return DriverResult::ErrorWritingData; + } + + disable_input_thread = true; + const auto result = nfc_protocol->WriteMifare(data); disable_input_thread = false; + return result; } 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: DriverResult SetIrMode(); DriverResult SetNfcMode(); DriverResult SetRingConMode(); + DriverResult StartNfcPolling(); + DriverResult StopNfcPolling(); + DriverResult ReadAmiiboData(std::vector<u8>& out_data); DriverResult WriteNfcData(std::span<const u8> data); + DriverResult ReadMifareData(std::span<const MifareReadChunk> request, + std::span<MifareReadData> out_data); + DriverResult WriteMifareData(std::span<const MifareWriteChunk> request); void SetCallbacks(const JoyconCallbacks& callbacks); 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 using MacAddress = std::array<u8, 6>; using SerialNumber = std::array<u8, 15>; using TagUUID = std::array<u8, 7>; +using MifareUUID = std::array<u8, 4>; enum class ControllerType : u8 { None = 0x00, @@ -307,6 +308,19 @@ enum class NFCStatus : u8 { WriteDone = 0x05, TagLost = 0x07, WriteReady = 0x09, + MifareDone = 0x10, +}; + +enum class MifareCmd : u8 { + None = 0x00, + Read = 0x30, + AuthA = 0x60, + AuthB = 0x61, + Write = 0xA0, + Transfer = 0xB0, + Decrement = 0xC0, + Increment = 0xC1, + Store = 0xC2 }; enum class IrsMode : u8 { @@ -592,6 +606,14 @@ struct NFCWriteCommandData { static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); #pragma pack(pop) +struct MifareCommandData { + u8 unknown1; + u8 unknown2; + u8 number_of_short_bytes; + MifareUUID uid; +}; +static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size"); + struct NFCPollingCommandData { u8 enable_mifare; u8 unknown_1; @@ -629,6 +651,41 @@ struct NFCWritePackage { std::array<NFCDataChunk, 4> data_chunks; }; +struct MifareReadChunk { + MifareCmd command; + std::array<u8, 0x6> sector_key; + u8 sector; +}; + +struct MifareWriteChunk { + MifareCmd command; + std::array<u8, 0x6> sector_key; + u8 sector; + std::array<u8, 0x10> data; +}; + +struct MifareReadData { + u8 sector; + std::array<u8, 0x10> data; +}; + +struct MifareReadPackage { + MifareCommandData command_data; + std::array<MifareReadChunk, 0x10> data_chunks; +}; + +struct MifareWritePackage { + MifareCommandData command_data; + std::array<MifareWriteChunk, 0x10> data_chunks; +}; + +struct TagInfo { + u8 uuid_length; + u8 protocol; + u8 tag_type; + std::array<u8, 10> uuid; +}; + struct IrsConfigure { MCUCommand command; MCUSubCommand sub_command; @@ -744,7 +801,7 @@ struct JoyconCallbacks { std::function<void(int, f32)> on_stick_data; std::function<void(int, const MotionData&)> on_motion_data; std::function<void(f32)> on_ring_data; - std::function<void(const std::vector<u8>&)> on_amiibo_data; + std::function<void(const Joycon::TagInfo&)> on_amiibo_data; std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; }; 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() { if (result == DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Ready); } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStopPollingRequest(output); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::Ready); + } + if (result == DriverResult::Success) { + is_enabled = true; + } return result; } @@ -54,37 +64,50 @@ DriverResult NfcProtocol::DisableNfc() { } is_enabled = false; + is_polling = false; return result; } DriverResult NfcProtocol::StartNFCPollingMode() { - LOG_DEBUG(Input, "Start NFC pooling Mode"); + LOG_DEBUG(Input, "Start NFC polling Mode"); ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; if (result == DriverResult::Success) { MCUCommandResponse output{}; - result = SendStopPollingRequest(output); + result = SendStartPollingRequest(output); } if (result == DriverResult::Success) { - result = WaitUntilNfcIs(NFCStatus::Ready); + result = WaitUntilNfcIs(NFCStatus::Polling); } if (result == DriverResult::Success) { + is_polling = true; + } + + return result; +} + +DriverResult NfcProtocol::StopNFCPollingMode() { + LOG_DEBUG(Input, "Stop NFC polling Mode"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + + if (result == DriverResult::Success) { MCUCommandResponse output{}; - result = SendStartPollingRequest(output); + result = SendStopPollingRequest(output); } if (result == DriverResult::Success) { - result = WaitUntilNfcIs(NFCStatus::Polling); + result = WaitUntilNfcIs(NFCStatus::WriteReady); } if (result == DriverResult::Success) { - is_enabled = true; + is_polling = false; } return result; } -DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { +DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { if (update_counter++ < AMIIBO_UPDATE_DELAY) { return DriverResult::Delayed; } @@ -100,11 +123,41 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { } if (result == DriverResult::Success) { + tag_info = { + .uuid_length = tag_data.uuid_size, + .protocol = 1, + .tag_type = tag_data.type, + .uuid = {}, + }; + + memcpy(tag_info.uuid.data(), tag_data.uuid.data(), tag_data.uuid_size); + + // Investigate why mifare type is not correct + if (tag_info.tag_type == 144) { + tag_info.tag_type = 1U << 6; + } + std::string uuid_string; for (auto& content : tag_data.uuid) { uuid_string += fmt::format(" {:02x}", content); } LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string); + } + + return result; +} + +DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) { + LOG_DEBUG(Input, "Scan for amiibos"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + TagFoundData tag_data{}; + + if (result == DriverResult::Success) { + result = IsTagInRange(tag_data, 7); + } + + if (result == DriverResult::Success) { result = GetAmiiboData(data); } @@ -154,6 +207,69 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { return result; } +DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request, + std::span<MifareReadData> out_data) { + LOG_DEBUG(Input, "Read mifare"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + TagFoundData tag_data{}; + MifareUUID tag_uuid{}; + + if (result == DriverResult::Success) { + result = IsTagInRange(tag_data, 7); + } + if (result == DriverResult::Success) { + memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); + result = GetMifareData(tag_uuid, read_request, out_data); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStopPollingRequest(output); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::Ready); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStartPollingRequest(output, true); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::WriteReady); + } + return result; +} + +DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) { + LOG_DEBUG(Input, "Write mifare"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + TagFoundData tag_data{}; + MifareUUID tag_uuid{}; + + if (result == DriverResult::Success) { + result = IsTagInRange(tag_data, 7); + } + if (result == DriverResult::Success) { + memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); + result = WriteMifareData(tag_uuid, write_request); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStopPollingRequest(output); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::Ready); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStartPollingRequest(output, true); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::WriteReady); + } + return result; +} + bool NfcProtocol::HasAmiibo() { if (update_counter++ < AMIIBO_UPDATE_DELAY) { return true; @@ -341,6 +457,158 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con return result; } +DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, + std::span<const MifareReadChunk> read_request, + std::span<MifareReadData> out_data) { + constexpr std::size_t timeout_limit = 60; + const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); + const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data); + std::span<const u8> buffer(nfc_buffer_data); + DriverResult result = DriverResult::Success; + MCUCommandResponse output{}; + u8 block_id = 1; + u8 package_index = 0; + std::size_t tries = 0; + std::size_t current_position = 0; + + LOG_INFO(Input, "Reading Mifare data"); + + // Send data request. Nfc buffer size is 31, Send the data in smaller packages + while (current_position < buffer.size() && tries++ < timeout_limit) { + const std::size_t next_position = + std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); + const std::size_t block_size = next_position - current_position; + const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); + + SendReadDataMifareRequest(output, block_id, is_last_packet, + buffer.subspan(current_position, block_size)); + + const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + // Increase position when data is confirmed by the joycon + if (output.mcu_report == MCUReport::NFCState && + (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && + output.mcu_data[3] == block_id) { + block_id++; + current_position = next_position; + } + } + + if (result != DriverResult::Success) { + return result; + } + + // Wait for reply and save the output data + while (tries++ < timeout_limit) { + result = SendNextPackageRequest(output, package_index); + const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); + + if (result != DriverResult::Success) { + return result; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { + constexpr std::size_t DATA_LENGHT = 0x10 + 1; + constexpr std::size_t DATA_START = 11; + const u8 number_of_elements = output.mcu_data[10]; + for (std::size_t i = 0; i < number_of_elements; i++) { + out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)]; + memcpy(out_data[i].data.data(), + output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT), + sizeof(MifareReadData::data)); + } + package_index++; + continue; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { + LOG_INFO(Input, "Finished reading mifare"); + break; + } + } + + return result; +} + +DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, + std::span<const MifareWriteChunk> write_request) { + constexpr std::size_t timeout_limit = 60; + const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); + const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data); + std::span<const u8> buffer(nfc_buffer_data); + DriverResult result = DriverResult::Success; + MCUCommandResponse output{}; + u8 block_id = 1; + u8 package_index = 0; + std::size_t tries = 0; + std::size_t current_position = 0; + + LOG_INFO(Input, "Writing Mifare data"); + + // Send data request. Nfc buffer size is 31, Send the data in smaller packages + while (current_position < buffer.size() && tries++ < timeout_limit) { + const std::size_t next_position = + std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); + const std::size_t block_size = next_position - current_position; + const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); + + SendReadDataMifareRequest(output, block_id, is_last_packet, + buffer.subspan(current_position, block_size)); + + const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + // Increase position when data is confirmed by the joycon + if (output.mcu_report == MCUReport::NFCState && + (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && + output.mcu_data[3] == block_id) { + block_id++; + current_position = next_position; + } + } + + if (result != DriverResult::Success) { + return result; + } + + // Wait for reply and ignore the output data + while (tries++ < timeout_limit) { + result = SendNextPackageRequest(output, package_index); + const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); + + if (result != DriverResult::Success) { + return result; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { + package_index++; + continue; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { + LOG_INFO(Input, "Finished writing mifare"); + break; + } + } + + return result; +} + DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, bool is_second_attempt) { NFCRequestState request{ @@ -477,6 +745,28 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, output); } +DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, + bool is_last_packet, std::span<const u8> data) { + const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); + NFCRequestState request{ + .command_argument = NFCCommand::Mifare, + .block_id = block_id, + .packet_id = {}, + .packet_flag = + is_last_packet ? MCUPacketFlag::LastCommandPacket : MCUPacketFlag::MorePacketsRemaining, + .data_length = static_cast<u8>(data_size), + .raw_data = {}, + .crc = {}, + }; + memcpy(request.raw_data.data(), data.data(), data_size); + + std::array<u8, sizeof(NFCRequestState)> request_data{}; + memcpy(request_data.data(), &request, sizeof(NFCRequestState)); + request_data[36] = CalculateMCU_CRC8(request_data.data(), 36); + return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data, + output); +} + std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { const std::size_t header_size = sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); @@ -498,6 +788,48 @@ std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& packag return serialized_data; } +std::vector<u8> NfcProtocol::SerializeMifareReadPackage(const MifareReadPackage& package) const { + const std::size_t header_size = sizeof(MifareCommandData); + std::vector<u8> serialized_data(header_size); + std::size_t start_index = 0; + + memcpy(serialized_data.data(), &package, header_size); + start_index += header_size; + + for (const auto& data_chunk : package.data_chunks) { + const std::size_t chunk_size = sizeof(MifareReadChunk); + if (data_chunk.command == MifareCmd::None) { + continue; + } + serialized_data.resize(start_index + chunk_size); + memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); + start_index += chunk_size; + } + + return serialized_data; +} + +std::vector<u8> NfcProtocol::SerializeMifareWritePackage(const MifareWritePackage& package) const { + const std::size_t header_size = sizeof(MifareCommandData); + std::vector<u8> serialized_data(header_size); + std::size_t start_index = 0; + + memcpy(serialized_data.data(), &package, header_size); + start_index += header_size; + + for (const auto& data_chunk : package.data_chunks) { + const std::size_t chunk_size = sizeof(MifareWriteChunk); + if (data_chunk.command == MifareCmd::None) { + continue; + } + serialized_data.resize(start_index + chunk_size); + memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); + start_index += chunk_size; + } + + return serialized_data; +} + NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const { return { @@ -527,6 +859,46 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, }; } +MifareReadPackage NfcProtocol::MakeMifareReadPackage( + const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request) const { + MifareReadPackage package{ + .command_data{ + .unknown1 = 0xd0, + .unknown2 = 0x07, + .number_of_short_bytes = static_cast<u8>( + ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID)) / 2), + .uid = tag_uuid, + }, + .data_chunks = {}, + }; + + for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { + package.data_chunks[i] = read_request[i]; + } + + return package; +} + +MifareWritePackage NfcProtocol::MakeMifareWritePackage( + const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> read_request) const { + MifareWritePackage package{ + .command_data{ + .unknown1 = 0xd0, + .unknown2 = 0x07, + .number_of_short_bytes = static_cast<u8>( + ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID) + 2) / 2), + .uid = tag_uuid, + }, + .data_chunks = {}, + }; + + for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { + package.data_chunks[i] = read_request[i]; + } + + return package; +} + NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { constexpr u8 NFC_PAGE_SIZE = 4; @@ -606,4 +978,8 @@ bool NfcProtocol::IsEnabled() const { return is_enabled; } +bool NfcProtocol::IsPolling() const { + return is_polling; +} + } // 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: DriverResult StartNFCPollingMode(); - DriverResult ScanAmiibo(std::vector<u8>& data); + DriverResult StopNFCPollingMode(); + + DriverResult GetTagInfo(Joycon::TagInfo& tag_info); + + DriverResult ReadAmiibo(std::vector<u8>& data); DriverResult WriteAmiibo(std::span<const u8> data); + DriverResult ReadMifare(std::span<const MifareReadChunk> read_request, + std::span<MifareReadData> out_data); + + DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request); + bool HasAmiibo(); bool IsEnabled() const; + bool IsPolling() const; + private: // Number of times the function will be delayed until it outputs valid data static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; @@ -51,6 +62,13 @@ private: DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); + DriverResult GetMifareData(const MifareUUID& tag_uuid, + std::span<const MifareReadChunk> read_request, + std::span<MifareReadData> out_data); + + DriverResult WriteMifareData(const MifareUUID& tag_uuid, + std::span<const MifareWriteChunk> write_request); + DriverResult SendStartPollingRequest(MCUCommandResponse& output, bool is_second_attempt = false); @@ -65,17 +83,31 @@ private: DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, bool is_last_packet, std::span<const u8> data); + DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, + bool is_last_packet, std::span<const u8> data); + std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; + std::vector<u8> SerializeMifareReadPackage(const MifareReadPackage& package) const; + + std::vector<u8> SerializeMifareWritePackage(const MifareWritePackage& package) const; + NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; + MifareReadPackage MakeMifareReadPackage(const MifareUUID& tag_uuid, + std::span<const MifareReadChunk> read_request) const; + + MifareWritePackage MakeMifareWritePackage(const MifareUUID& tag_uuid, + std::span<const MifareWriteChunk> read_request) const; + NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; TagUUID GetTagUUID(std::span<const u8> data) const; bool is_enabled{}; + bool is_polling{}; std::size_t update_counter{}; }; 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) { callbacks.on_color_data(color); } -void JoyconPoller::UpdateAmiibo(const std::vector<u8>& amiibo_data) { - callbacks.on_amiibo_data(amiibo_data); +void JoyconPoller::UpdateAmiibo(const Joycon::TagInfo& tag_info) { + callbacks.on_amiibo_data(tag_info); } 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: void UpdateColor(const Color& color); void UpdateRing(s16 value, const RingStatus& ring_status); - void UpdateAmiibo(const std::vector<u8>& amiibo_data); - void UpdateCamera(const std::vector<u8>& amiibo_data, IrsResolution format); + void UpdateAmiibo(const Joycon::TagInfo& tag_info); + void UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format); private: void UpdateActiveLeftPadInput(const InputReportActive& input, diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 50b5a3dc8..c2d0cbb34 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -143,12 +143,46 @@ public: return Common::Input::NfcState::NotSupported; } + // Start scanning for nfc tags + virtual Common::Input::NfcState StartNfcPolling( + [[maybe_unused]] const PadIdentifier& identifier_) { + return Common::Input::NfcState::NotSupported; + } + + // Start scanning for nfc tags + virtual Common::Input::NfcState StopNfcPolling( + [[maybe_unused]] const PadIdentifier& identifier_) { + return Common::Input::NfcState::NotSupported; + } + + // Reads data from amiibo tag + virtual Common::Input::NfcState ReadAmiiboData( + [[maybe_unused]] const PadIdentifier& identifier_, + [[maybe_unused]] std::vector<u8>& out_data) { + return Common::Input::NfcState::NotSupported; + } + // Writes data to an nfc tag virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier, [[maybe_unused]] const std::vector<u8>& data) { return Common::Input::NfcState::NotSupported; } + // Reads data from mifare tag + virtual Common::Input::NfcState ReadMifareData( + [[maybe_unused]] const PadIdentifier& identifier_, + [[maybe_unused]] const Common::Input::MifareRequest& request, + [[maybe_unused]] Common::Input::MifareRequest& out_data) { + return Common::Input::NfcState::NotSupported; + } + + // Write data to mifare tag + virtual Common::Input::NfcState WriteMifareData( + [[maybe_unused]] const PadIdentifier& identifier_, + [[maybe_unused]] const Common::Input::MifareRequest& request) { + return Common::Input::NfcState::NotSupported; + } + // Returns the engine name [[nodiscard]] const std::string& GetEngineName() const; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 380a01542..870e76ab0 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -792,8 +792,7 @@ public: const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Nfc, - .nfc_status = nfc_status.state, - .raw_data = nfc_status.data, + .nfc_status = nfc_status, }; TriggerOnChange(status); @@ -836,10 +835,31 @@ public: return input_engine->SupportsNfc(identifier); } + Common::Input::NfcState StartNfcPolling() { + return input_engine->StartNfcPolling(identifier); + } + + Common::Input::NfcState StopNfcPolling() { + return input_engine->StopNfcPolling(identifier); + } + + Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) { + return input_engine->ReadAmiiboData(identifier, out_data); + } + Common::Input::NfcState WriteNfcData(const std::vector<u8>& data) override { return input_engine->WriteNfcData(identifier, data); } + Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) { + return input_engine->ReadMifareData(identifier, request, out_data); + } + + Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) { + return input_engine->WriteMifareData(identifier, request); + } + private: const PadIdentifier identifier; InputEngine* input_engine; |