From 8eebb83c2c40901e098178a47886a7a98aa550b2 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Wed, 12 Jul 2023 15:01:08 -0600 Subject: [PATCH] service: nfc: Keep tag alive while it's being used (#6687) --- src/core/hle/service/nfc/nfc.cpp | 18 +++++++++++++++ src/core/hle/service/nfc/nfc_device.cpp | 30 +++++++++++++++++-------- src/core/hle/service/nfc/nfc_device.h | 7 +++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index d582066731..3c0963de64 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -175,6 +175,8 @@ void Module::Interface::Mount(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + ResultCode result = RESULT_SUCCESS; switch (nfc->nfc_mode) { case CommunicationMode::Ntag: @@ -310,6 +312,8 @@ void Module::Interface::GetTagInfo2(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode == CommunicationMode::TrainTag) { LOG_ERROR(Service_NFC, "CommunicationMode {} not implemented", nfc->nfc_mode); IPC::RequestBuilder rb = rp.MakeBuilder(26, 0); @@ -330,6 +334,8 @@ void Module::Interface::GetTagInfo(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode == CommunicationMode::TrainTag) { LOG_ERROR(Service_NFC, "CommunicationMode {} not implemented", nfc->nfc_mode); IPC::RequestBuilder rb = rp.MakeBuilder(12, 0); @@ -360,6 +366,8 @@ void Module::Interface::OpenApplicationArea(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called, access_id={}", access_id); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode != CommunicationMode::Amiibo) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultInvalidOperation); @@ -397,6 +405,8 @@ void Module::Interface::ReadApplicationArea(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode != CommunicationMode::Amiibo) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultInvalidOperation); @@ -436,6 +446,8 @@ void Module::Interface::GetNfpRegisterInfo(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode != CommunicationMode::Amiibo) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultInvalidOperation); @@ -455,6 +467,8 @@ void Module::Interface::GetNfpCommonInfo(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode != CommunicationMode::Amiibo) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultInvalidOperation); @@ -515,6 +529,8 @@ void Module::Interface::GetIdentificationBlock(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode != CommunicationMode::Amiibo) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultInvalidOperation); @@ -548,6 +564,8 @@ void Module::Interface::GetAdminInfo(Kernel::HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); + nfc->device->RescheduleTagRemoveEvent(); + if (nfc->nfc_mode != CommunicationMode::Amiibo) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultInvalidOperation); diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp index 58fd6fc8ef..a48859ebd6 100644 --- a/src/core/hle/service/nfc/nfc_device.cpp +++ b/src/core/hle/service/nfc/nfc_device.cpp @@ -38,10 +38,7 @@ void NfcDevice::serialize(Archive& ar, const unsigned int) { } SERIALIZE_IMPL(NfcDevice) -/// The interval at which the amiibo will be removed automatically 1.5s -static constexpr u64 amiibo_removal_interval_us = 268 * 1000 * 1000; - -NfcDevice::NfcDevice(Core::System& system) { +NfcDevice::NfcDevice(Core::System& system_) : system{system_} { tag_in_range_event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NFC::tag_in_range_event"); tag_out_of_range_event = @@ -88,8 +85,7 @@ bool NfcDevice::LoadAmiibo(std::string filename) { tag_out_of_range_event->Clear(); tag_in_range_event->Signal(); - Core::System::GetInstance().CoreTiming().ScheduleEvent(amiibo_removal_interval_us, - remove_amiibo_event); + RescheduleTagRemoveEvent(); // Fallback for plain amiibos if (is_plain_amiibo) { @@ -270,6 +266,9 @@ ResultCode NfcDevice::Flush() { return connection_result; } + // Ensure the tag will not be removed in the middle of a write + RescheduleTagRemoveEvent(); + auto& settings = tag.file.settings; const auto& current_date = GetAmiiboDate(); @@ -888,8 +887,7 @@ ResultCode NfcDevice::RecreateApplicationArea(u32 access_id, std::span } u64 application_id{}; - if (Core::System::GetInstance().GetAppLoader().ReadProgramId(application_id) == - Loader::ResultStatus::Success) { + if (system.GetAppLoader().ReadProgramId(application_id) == Loader::ResultStatus::Success) { tag.file.application_id_byte = static_cast(application_id >> application_id_version_offset & 0xf); tag.file.application_id = @@ -1008,7 +1006,7 @@ void NfcDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo } time_t NfcDevice::GetCurrentTime() const { - auto& share_page = Core::System::GetInstance().Kernel().GetSharedPageHandler(); + auto& share_page = system.Kernel().GetSharedPageHandler(); const auto console_time = share_page.GetSharedPage().date_time_1.date_time / 1000; // 3DS console time uses Jan 1 1900 as internal epoch, @@ -1111,4 +1109,18 @@ void NfcDevice::BuildAmiiboWithoutKeys() { settings.settings.appdata_initialized.Assign(0); } +void NfcDevice::RescheduleTagRemoveEvent() { + /// The interval at which the amiibo will be removed automatically 1.5s + static constexpr u64 amiibo_removal_interval = nsToCycles(1500 * 1000 * 1000); + + system.CoreTiming().UnscheduleEvent(remove_amiibo_event, 0); + + if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted && + device_state != DeviceState::TagPartiallyMounted) { + return; + } + + system.CoreTiming().ScheduleEvent(amiibo_removal_interval, remove_amiibo_event); +} + } // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h index dc6d283613..b241010487 100644 --- a/src/core/hle/service/nfc/nfc_device.h +++ b/src/core/hle/service/nfc/nfc_device.h @@ -21,7 +21,7 @@ class KReadableEvent; namespace Service::NFC { class NfcDevice { public: - NfcDevice(Core::System& system); + NfcDevice(Core::System& system_); ~NfcDevice(); bool LoadAmiibo(std::string filename); @@ -71,6 +71,10 @@ public: std::shared_ptr GetActivateEvent() const; std::shared_ptr GetDeactivateEvent() const; + /// Automatically removes the nfc tag after x ammount of time. + /// If called multiple times the counter will be restarted. + void RescheduleTagRemoveEvent(); + private: time_t GetCurrentTime() const; void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name); @@ -100,6 +104,7 @@ private: SerializableAmiiboFile tag{}; SerializableEncryptedAmiiboFile encrypted_tag{}; + Core::System& system; template void serialize(Archive& ar, const unsigned int);