From 94151097b9abadf35c55ea06a31925c9848f4c62 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Wed, 19 Apr 2023 19:01:23 -0600 Subject: service: nfc: Merge device interfaces and create the device manager --- src/core/hle/service/nfc/nfc_interface.cpp | 399 ++++++++++++++++------------- 1 file changed, 221 insertions(+), 178 deletions(-) (limited to 'src/core/hle/service/nfc/nfc_interface.cpp') diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp index be96d0cbc..0fa29d398 100644 --- a/src/core/hle/service/nfc/nfc_interface.cpp +++ b/src/core/hle/service/nfc/nfc_interface.cpp @@ -6,55 +6,56 @@ #include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/nfc/nfc_device.h" +#include "core/hle/service/nfc/common/device.h" +#include "core/hle/service/nfc/common/device_manager.h" +#include "core/hle/service/nfc/mifare_result.h" +#include "core/hle/service/nfc/mifare_types.h" #include "core/hle/service/nfc/nfc_interface.h" #include "core/hle/service/nfc/nfc_result.h" +#include "core/hle/service/nfc/nfc_types.h" +#include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/time/clock_types.h" namespace Service::NFC { -Interface::Interface(Core::System& system_, const char* name) - : ServiceFramework{system_, name}, service_context{system_, service_name} { - availability_change_event = service_context.CreateEvent("Interface:AvailabilityChangeEvent"); +NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend) + : ServiceFramework{system_, name}, service_context{system_, service_name}, + backend_type{service_backend} {} - for (u32 device_index = 0; device_index < 10; device_index++) { - devices[device_index] = - std::make_shared(Core::HID::IndexToNpadIdType(device_index), system, - service_context, availability_change_event); - } -} +NfcInterface ::~NfcInterface() = default; -Interface ::~Interface() { - availability_change_event->Close(); -} - -void Interface::Initialize(HLERequestContext& ctx) { +void NfcInterface::Initialize(HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); - state = State::Initialized; + auto manager = GetManager(); + auto result = manager->Initialize(); - for (auto& device : devices) { - device->Initialize(); + if (result.IsSuccess()) { + state = State::Initialized; + } else { + manager->Finalize(); } IPC::ResponseBuilder rb{ctx, 2, 0}; - rb.Push(ResultSuccess); + rb.Push(result); } -void Interface::Finalize(HLERequestContext& ctx) { +void NfcInterface::Finalize(HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); - state = State::NonInitialized; - - for (auto& device : devices) { - device->Finalize(); + if (state != State::NonInitialized) { + if (GetBackendType() != BackendType::None) { + GetManager()->Finalize(); + } + device_manager = nullptr; + state = State::NonInitialized; } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } -void Interface::GetState(HLERequestContext& ctx) { +void NfcInterface::GetState(HLERequestContext& ctx) { LOG_DEBUG(Service_NFC, "called"); IPC::ResponseBuilder rb{ctx, 3}; @@ -62,50 +63,28 @@ void Interface::GetState(HLERequestContext& ctx) { rb.PushEnum(state); } -void Interface::IsNfcEnabled(HLERequestContext& ctx) { +void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) { LOG_DEBUG(Service_NFC, "called"); + // TODO: This calls nn::settings::detail::GetNfcEnableFlag + const bool is_enabled = true; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(state != State::NonInitialized); + rb.Push(is_enabled); } -void Interface::ListDevices(HLERequestContext& ctx) { - LOG_DEBUG(Service_NFC, "called"); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - if (!ctx.CanWriteBuffer()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidArgument); - return; - } - - if (ctx.GetWriteBufferSize() == 0) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidArgument); - return; - } - +void NfcInterface::ListDevices(HLERequestContext& ctx) { std::vector nfp_devices; const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements(); + LOG_DEBUG(Service_NFC, "called"); - for (auto& device : devices) { - if (nfp_devices.size() >= max_allowed_devices) { - continue; - } - if (device->GetCurrentState() != NFP::DeviceState::Unavailable) { - nfp_devices.push_back(device->GetHandle()); - } - } + auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices); + result = TranslateResultToServiceError(result); - if (nfp_devices.empty()) { + if (result.IsError()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); + rb.Push(result); return; } @@ -116,210 +95,177 @@ void Interface::ListDevices(HLERequestContext& ctx) { rb.Push(static_cast(nfp_devices.size())); } -void Interface::GetDeviceState(HLERequestContext& ctx) { +void NfcInterface::GetDeviceState(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); - auto device = GetNfcDevice(device_handle); + const auto device_state = GetManager()->GetDeviceState(device_handle); - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; + if (device_state > DeviceState::Finalized) { + ASSERT_MSG(false, "Invalid device state"); } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(device.value()->GetCurrentState()); + rb.PushEnum(device_state); } -void Interface::GetNpadId(HLERequestContext& ctx) { +void NfcInterface::GetNpadId(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfcDevice(device_handle); + Core::HID::NpadIdType npad_id{}; + auto result = GetManager()->GetNpadId(device_handle, npad_id); + result = TranslateResultToServiceError(result); - if (!device.has_value()) { + if (result.IsError()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); + rb.Push(result); return; } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(device.value()->GetNpadId()); + rb.PushEnum(npad_id); } -void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { +void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called"); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(availability_change_event->GetReadableEvent()); + rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent()); } -void Interface::StartDetection(HLERequestContext& ctx) { +void NfcInterface::StartDetection(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; - const auto nfp_protocol{rp.PopEnum()}; - LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); + const auto tag_protocol{rp.PopEnum()}; + LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfcDevice(device_handle); + auto result = GetManager()->StartDetection(device_handle, tag_protocol); + result = TranslateResultToServiceError(result); - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->StartDetection(nfp_protocol); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); } -void Interface::StopDetection(HLERequestContext& ctx) { +void NfcInterface::StopDetection(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfcDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } + auto result = GetManager()->StopDetection(device_handle); + result = TranslateResultToServiceError(result); - const auto result = device.value()->StopDetection(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); } -void Interface::GetTagInfo(HLERequestContext& ctx) { +void NfcInterface::GetTagInfo(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } + TagInfo tag_info{}; + auto result = + GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare); + result = TranslateResultToServiceError(result); - auto device = GetNfcDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; + if (result.IsSuccess()) { + ctx.WriteBuffer(tag_info); } - NFP::TagInfo tag_info{}; - const auto result = device.value()->GetTagInfo(tag_info, false); - ctx.WriteBuffer(tag_info); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); } -void Interface::AttachActivateEvent(HLERequestContext& ctx) { +void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfcDevice(device_handle); + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle)); +} - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } +void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(device.value()->GetActivateEvent()); + rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle)); } -void Interface::AttachDeactivateEvent(HLERequestContext& ctx) { +void NfcInterface::ReadMifare(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; - LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + const auto buffer{ctx.ReadBuffer()}; + const auto number_of_commands{ctx.GetReadBufferNumElements()}; + std::vector read_commands(number_of_commands); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } + memcpy(read_commands.data(), buffer.data(), + number_of_commands * sizeof(MifareReadBlockParameter)); - auto device = GetNfcDevice(device_handle); + LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", + device_handle, number_of_commands); - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; + std::vector out_data(number_of_commands); + auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data); + result = TranslateResultToServiceError(result); + + if (result.IsSuccess()) { + ctx.WriteBuffer(out_data); } - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(device.value()->GetDeactivateEvent()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void NfcInterface::WriteMifare(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto buffer{ctx.ReadBuffer()}; + const auto number_of_commands{ctx.GetReadBufferNumElements()}; + std::vector write_commands(number_of_commands); + + memcpy(write_commands.data(), buffer.data(), + number_of_commands * sizeof(MifareWriteBlockParameter)); + + LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}", + device_handle, number_of_commands); + + auto result = GetManager()->WriteMifare(device_handle, write_commands); + result = TranslateResultToServiceError(result); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); } -void Interface::SendCommandByPassThrough(HLERequestContext& ctx) { +void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; const auto timeout{rp.PopRaw()}; const auto command_data{ctx.ReadBuffer()}; - LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", device_handle, timeout.ToSeconds(), command_data.size()); - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfcDevice(device_handle); + std::vector out_data(1); + auto result = + GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data); + result = TranslateResultToServiceError(result); - if (!device.has_value()) { + if (result.IsError()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); + rb.Push(result); return; } - std::vector out_data(1); - // TODO: Request data from nfc device ctx.WriteBuffer(out_data); IPC::ResponseBuilder rb{ctx, 3}; @@ -327,13 +273,110 @@ void Interface::SendCommandByPassThrough(HLERequestContext& ctx) { rb.Push(static_cast(out_data.size())); } -std::optional> Interface::GetNfcDevice(u64 handle) { - for (auto& device : devices) { - if (device->GetHandle() == handle) { - return device; +std::shared_ptr NfcInterface::GetManager() { + if (device_manager == nullptr) { + device_manager = std::make_shared(system, service_context); + } + return device_manager; +} + +BackendType NfcInterface::GetBackendType() const { + return backend_type; +} + +Result NfcInterface::TranslateResultToServiceError(Result result) const { + const auto backend = GetBackendType(); + + if (result.IsSuccess()) { + return result; + } + + if (result.module != ErrorModule::NFC) { + return result; + } + + switch (backend) { + case BackendType::Mifare: + return TranslateResultToNfp(result); + case BackendType::Nfp: { + return TranslateResultToNfp(result); + } + default: + if (result != ResultUnknown216) { + return result; } + return ResultUnknown74; + } +} + +Result NfcInterface::TranslateResultToNfp(Result result) const { + if (result == ResultDeviceNotFound) { + return NFP::ResultDeviceNotFound; + } + if (result == ResultInvalidArgument) { + return NFP::ResultInvalidArgument; + } + if (result == ResultWrongApplicationAreaSize) { + return NFP::ResultWrongApplicationAreaSize; + } + if (result == ResultWrongDeviceState) { + return NFP::ResultWrongDeviceState; + } + if (result == ResultUnknown74) { + return NFP::ResultUnknown74; + } + if (result == ResultNfcDisabled) { + return NFP::ResultNfcDisabled; + } + if (result == ResultNfcNotInitialized) { + return NFP::ResultNfcDisabled; + } + if (result == ResultWriteAmiiboFailed) { + return NFP::ResultWriteAmiiboFailed; + } + if (result == ResultTagRemoved) { + return NFP::ResultTagRemoved; + } + if (result == ResultRegistrationIsNotInitialized) { + return NFP::ResultRegistrationIsNotInitialized; + } + if (result == ResultApplicationAreaIsNotInitialized) { + return NFP::ResultApplicationAreaIsNotInitialized; + } + if (result == ResultCorruptedData) { + return NFP::ResultCorruptedData; + } + if (result == ResultWrongApplicationAreaId) { + return NFP::ResultWrongApplicationAreaId; + } + if (result == ResultApplicationAreaExist) { + return NFP::ResultApplicationAreaExist; + } + if (result == ResultNotAnAmiibo) { + return NFP::ResultNotAnAmiibo; + } + LOG_WARNING(Service_NFC, "Result conversion not handled"); + return result; +} + +Result NfcInterface::TranslateResultToMifare(Result result) const { + if (result == ResultDeviceNotFound) { + return Mifare::ResultDeviceNotFound; + } + if (result == ResultInvalidArgument) { + return Mifare::ResultInvalidArgument; + } + if (result == ResultWrongDeviceState) { + return Mifare::ResultWrongDeviceState; + } + if (result == ResultNfcDisabled) { + return Mifare::ResultNfcDisabled; + } + if (result == ResultTagRemoved) { + return Mifare::ResultTagRemoved; } - return std::nullopt; + LOG_WARNING(Service_NFC, "Result conversion not handled"); + return result; } } // namespace Service::NFC -- cgit v1.2.3