From 8a3d22c4bd54c18edb51fe6513761ec2189e3369 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 24 Sep 2022 20:36:40 -0500 Subject: core: hid: Add nfc support to emulated controller --- src/core/hid/emulated_controller.cpp | 70 ++++++++++++++++++++++++++++++++++++ src/core/hid/emulated_controller.h | 34 ++++++++++++++++-- src/core/hid/input_converter.cpp | 14 ++++++++ src/core/hid/input_converter.h | 8 +++++ 4 files changed, 123 insertions(+), 3 deletions(-) (limited to 'src/core/hid') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 01c43be93..142c39003 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -131,13 +131,16 @@ void EmulatedController::LoadDevices() { battery_params[RightIndex].Set("battery", true); camera_params = Common::ParamPackage{"engine:camera,camera:1"}; + nfc_params = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; output_params[LeftIndex] = left_joycon; output_params[RightIndex] = right_joycon; output_params[2] = camera_params; + output_params[3] = nfc_params; output_params[LeftIndex].Set("output", true); output_params[RightIndex].Set("output", true); output_params[2].Set("output", true); + output_params[3].Set("output", true); LoadTASParams(); @@ -155,6 +158,7 @@ void EmulatedController::LoadDevices() { std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), Common::Input::CreateDevice); camera_devices = Common::Input::CreateDevice(camera_params); + nfc_devices = Common::Input::CreateDevice(nfc_params); std::transform(output_params.begin(), output_params.end(), output_devices.begin(), Common::Input::CreateDevice); @@ -284,6 +288,16 @@ void EmulatedController::ReloadInput() { camera_devices->ForceUpdate(); } + if (nfc_devices) { + if (npad_id_type == NpadIdType::Handheld || npad_id_type == NpadIdType::Player1) { + nfc_devices->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); }, + }); + nfc_devices->ForceUpdate(); + } + } + // Use a common UUID for TAS static constexpr Common::UUID TAS_UUID = Common::UUID{ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; @@ -339,6 +353,8 @@ void EmulatedController::UnloadInput() { for (auto& stick : tas_stick_devices) { stick.reset(); } + camera_devices.reset(); + nfc_devices.reset(); } void EmulatedController::EnableConfiguration() { @@ -903,6 +919,25 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback TriggerOnChange(ControllerTriggerType::IrSensor, true); } +void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { + std::unique_lock lock{mutex}; + controller.nfc_values = TransformToNfc(callback); + + if (is_configuring) { + lock.unlock(); + TriggerOnChange(ControllerTriggerType::Nfc, false); + return; + } + + controller.nfc_state = { + controller.nfc_values.state, + controller.nfc_values.data, + }; + + lock.unlock(); + TriggerOnChange(ControllerTriggerType::Nfc, true); +} + bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { if (device_index >= output_devices.size()) { return false; @@ -980,6 +1015,10 @@ bool EmulatedController::TestVibration(std::size_t device_index) { bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { LOG_INFO(Service_HID, "Set polling mode {}", polling_mode); auto& output_device = output_devices[static_cast(DeviceIndex::Right)]; + auto& nfc_output_device = output_devices[3]; + + nfc_output_device->SetPollingMode(polling_mode); + return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None; } @@ -1000,6 +1039,32 @@ bool EmulatedController::SetCameraFormat( camera_format)) == Common::Input::CameraError::None; } +bool EmulatedController::HasNfc() const { + const auto& nfc_output_device = output_devices[3]; + + switch (npad_type) { + case NpadStyleIndex::JoyconRight: + case NpadStyleIndex::JoyconDual: + case NpadStyleIndex::ProController: + break; + default: + return false; + } + + const bool has_virtual_nfc = + npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld; + const bool is_virtual_nfc_supported = + nfc_output_device->SupportsNfc() != Common::Input::NfcState::NotSupported; + + return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); +} + +bool EmulatedController::WriteNfc(const std::vector& data) { + auto& nfc_output_device = output_devices[3]; + + return nfc_output_device->WriteNfcData(data) == Common::Input::NfcState::Success; +} + void EmulatedController::SetLedPattern() { for (auto& device : output_devices) { if (!device) { @@ -1363,6 +1428,11 @@ const CameraState& EmulatedController::GetCamera() const { return controller.camera_state; } +const NfcState& EmulatedController::GetNfc() const { + std::scoped_lock lock{mutex}; + return controller.nfc_state; +} + NpadColor EmulatedController::GetNpadColor(u32 color) { return { .r = static_cast((color >> 16) & 0xFF), diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index c3aa8f9d3..319226bf8 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -20,7 +20,7 @@ namespace Core::HID { const std::size_t max_emulated_controllers = 2; -const std::size_t output_devices = 3; +const std::size_t output_devices_size = 4; struct ControllerMotionInfo { Common::Input::MotionStatus raw_status{}; MotionInput emulated{}; @@ -37,7 +37,8 @@ using TriggerDevices = using BatteryDevices = std::array, max_emulated_controllers>; using CameraDevices = std::unique_ptr; -using OutputDevices = std::array, output_devices>; +using NfcDevices = std::unique_ptr; +using OutputDevices = std::array, output_devices_size>; using ButtonParams = std::array; using StickParams = std::array; @@ -45,7 +46,8 @@ using ControllerMotionParams = std::array; using BatteryParams = std::array; using CameraParams = Common::ParamPackage; -using OutputParams = std::array; +using NfcParams = Common::ParamPackage; +using OutputParams = std::array; using ButtonValues = std::array; using SticksValues = std::array; @@ -55,6 +57,7 @@ using ControllerMotionValues = std::array; using BatteryValues = std::array; using CameraValues = Common::Input::CameraStatus; +using NfcValues = Common::Input::NfcStatus; using VibrationValues = std::array; struct AnalogSticks { @@ -80,6 +83,11 @@ struct CameraState { std::size_t sample{}; }; +struct NfcState { + Common::Input::NfcState state{}; + std::vector data{}; +}; + struct ControllerMotion { Common::Vec3f accel{}; Common::Vec3f gyro{}; @@ -107,6 +115,7 @@ struct ControllerStatus { BatteryValues battery_values{}; VibrationValues vibration_values{}; CameraValues camera_values{}; + NfcValues nfc_values{}; // Data for HID serices HomeButtonState home_button_state{}; @@ -119,6 +128,7 @@ struct ControllerStatus { ControllerColors colors_state{}; BatteryLevelState battery_state{}; CameraState camera_state{}; + NfcState nfc_state{}; }; enum class ControllerTriggerType { @@ -130,6 +140,7 @@ enum class ControllerTriggerType { Battery, Vibration, IrSensor, + Nfc, Connected, Disconnected, Type, @@ -315,6 +326,9 @@ public: /// Returns the latest camera status from the controller const CameraState& GetCamera() const; + /// Returns the latest ntag status from the controller + const NfcState& GetNfc() const; + /** * Sends a specific vibration to the output device * @return true if vibration had no errors @@ -341,6 +355,12 @@ public: */ bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format); + /// Returns true if the device has nfc support + bool HasNfc() const; + + /// Returns true if the nfc tag was written + bool WriteNfc(const std::vector& data); + /// Returns the led pattern corresponding to this emulated controller LedPattern GetLedPattern() const; @@ -424,6 +444,12 @@ private: */ void SetCamera(const Common::Input::CallbackStatus& callback); + /** + * Updates the nfc status of the controller + * @param callback A CallbackStatus containing the nfc status + */ + void SetNfc(const Common::Input::CallbackStatus& callback); + /** * Converts a color format from bgra to rgba * @param color in bgra format @@ -458,6 +484,7 @@ private: TriggerParams trigger_params; BatteryParams battery_params; CameraParams camera_params; + NfcParams nfc_params; OutputParams output_params; ButtonDevices button_devices; @@ -466,6 +493,7 @@ private: TriggerDevices trigger_devices; BatteryDevices battery_devices; CameraDevices camera_devices; + NfcDevices nfc_devices; OutputDevices output_devices; // TAS related variables diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 52fb69e9c..e7b871acc 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -287,6 +287,20 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu return camera; } +Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback) { + Common::Input::NfcStatus nfc{}; + switch (callback.type) { + case Common::Input::InputType::Nfc: + nfc = callback.nfc_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); + break; + } + + return nfc; +} + void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; float& raw_value = analog.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index 143c50cc0..b7eb6e660 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -84,6 +84,14 @@ Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatu */ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback); +/** + * Converts raw input data into a valid nfc status. + * + * @param callback Supported callbacks: Nfc. + * @return A valid CameraObject object. + */ +Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback); + /** * Converts raw analog data into a valid analog value * @param analog An analog object containing raw data and properties -- cgit v1.2.3 From 3ce0ef04ddcb2420b61f8c6d22f8039fb7359856 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 24 Sep 2022 22:52:33 -0500 Subject: service: nfp: address comments --- src/common/input.h | 2 +- src/core/hid/input_converter.cpp | 2 +- src/core/hle/service/nfp/nfp_device.cpp | 11 ++++++----- src/core/hle/service/nfp/nfp_device.h | 4 ++-- src/core/hle/service/nfp/nfp_types.h | 25 +++++++++++++------------ src/input_common/drivers/virtual_amiibo.cpp | 4 ++-- src/input_common/drivers/virtual_amiibo.h | 2 +- src/input_common/input_engine.h | 3 ++- src/input_common/input_poller.cpp | 2 +- 9 files changed, 29 insertions(+), 26 deletions(-) (limited to 'src/core/hid') diff --git a/src/common/input.h b/src/common/input.h index 8365cc36e..bfa0639f5 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -332,7 +332,7 @@ public: return CameraError::NotSupported; } - virtual NfcState SupportsNfc() { + virtual NfcState SupportsNfc() const { return NfcState::NotSupported; } diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index e7b871acc..fe9915abe 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -291,7 +291,7 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal Common::Input::NfcStatus nfc{}; switch (callback.type) { case Common::Input::InputType::Nfc: - nfc = callback.nfc_status; + return callback.nfc_status; break; default: LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index da7daae88..ce3bcccf4 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -42,10 +42,11 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, } NfpDevice::~NfpDevice() { - if (is_controller_set) { - npad_device->DeleteCallback(callback_key); - is_controller_set = false; + if (!is_controller_set) { + return; } + npad_device->DeleteCallback(callback_key); + is_controller_set = false; }; void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { @@ -453,7 +454,7 @@ Result NfpDevice::SetApplicationArea(const std::vector& data) { return ResultSuccess; } -Result NfpDevice::CreateApplicationArea(u32 access_id, const std::vector& data) { +Result NfpDevice::CreateApplicationArea(u32 access_id, std::span data) { if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); if (device_state == DeviceState::TagRemoved) { @@ -470,7 +471,7 @@ Result NfpDevice::CreateApplicationArea(u32 access_id, const std::vector& da return RecreateApplicationArea(access_id, data); } -Result NfpDevice::RecreateApplicationArea(u32 access_id, const std::vector& data) { +Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span data) { if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); if (device_state == DeviceState::TagRemoved) { diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 53cc0833f..9ceb7b8fd 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -56,8 +56,8 @@ public: Result OpenApplicationArea(u32 access_id); Result GetApplicationArea(std::vector& data) const; Result SetApplicationArea(const std::vector& data); - Result CreateApplicationArea(u32 access_id, const std::vector& data); - Result RecreateApplicationArea(u32 access_id, const std::vector& data); + Result CreateApplicationArea(u32 access_id, std::span data); + Result RecreateApplicationArea(u32 access_id, std::span data); Result DeleteApplicationArea(); u64 GetHandle() const; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index d58657a21..2685ae8fe 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -5,6 +5,7 @@ #include +#include "common/swap.h" #include "core/hle/service/mii/types.h" namespace Service::NFP { @@ -80,33 +81,33 @@ using ApplicationArea = std::array; using AmiiboName = std::array; struct AmiiboDate { - u16_be raw_date{}; + u16 raw_date{}; - u16 DateRaw() const { - return static_cast(raw_date); + u16 GetValue() const { + return Common::swap16(raw_date); } u16 GetYear() const { - return static_cast(((DateRaw() & 0xFE00) >> 9) + 2000); + return static_cast(((GetValue() & 0xFE00) >> 9) + 2000); } u8 GetMonth() const { - return static_cast(((DateRaw() & 0x01E0) >> 5) - 1); + return static_cast(((GetValue() & 0x01E0) >> 5) - 1); } u8 GetDay() const { - return static_cast(DateRaw() & 0x001F); + return static_cast(GetValue() & 0x001F); } void SetYear(u16 year) { - raw_date = DateRaw() & ~0xFE00; - raw_date |= static_cast((year - 2000) << 9); + const u16 year_converted = static_cast((year - 2000) << 9); + raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); } void SetMonth(u8 month) { - raw_date = DateRaw() & ~0x01E0; - raw_date |= static_cast((month + 1) << 5); + const u16 month_converted = static_cast((month + 1) << 5); + raw_date = Common::swap16((GetValue() & ~0x01E0) | month_converted); } void SetDay(u8 day) { - raw_date = DateRaw() & ~0x001F; - raw_date |= static_cast(day); + const u16 day_converted = static_cast(day); + raw_date = Common::swap16((GetValue() & ~0x001F) | day_converted); } }; static_assert(sizeof(AmiiboDate) == 2, "AmiiboDate is an invalid size"); diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 8fadb1322..0cd5129da 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -20,7 +20,7 @@ constexpr PadIdentifier identifier = { VirtualAmiibo::VirtualAmiibo(std::string input_engine_) : InputEngine(std::move(input_engine_)) {} -VirtualAmiibo::~VirtualAmiibo() {} +VirtualAmiibo::~VirtualAmiibo() = default; Common::Input::PollingError VirtualAmiibo::SetPollingMode( [[maybe_unused]] const PadIdentifier& identifier_, @@ -41,7 +41,7 @@ Common::Input::PollingError VirtualAmiibo::SetPollingMode( } Common::Input::NfcState VirtualAmiibo::SupportsNfc( - [[maybe_unused]] const PadIdentifier& identifier_) { + [[maybe_unused]] const PadIdentifier& identifier_) const { return Common::Input::NfcState::Success; } diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 5790e4a1f..9eac07544 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -39,7 +39,7 @@ public: Common::Input::PollingError SetPollingMode( const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; - Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) override; + Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, const std::vector& data) override; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 9b8470c6f..cfbdb26bd 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -129,7 +129,8 @@ public: } // Request nfc data from a controller - virtual Common::Input::NfcState SupportsNfc([[maybe_unused]] const PadIdentifier& identifier) { + virtual Common::Input::NfcState SupportsNfc( + [[maybe_unused]] const PadIdentifier& identifier) const { return Common::Input::NfcState::NotSupported; } diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index a8eb1442b..75705b67e 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -768,7 +768,7 @@ public: return input_engine->SetCameraFormat(identifier, camera_format); } - Common::Input::NfcState SupportsNfc() override { + Common::Input::NfcState SupportsNfc() const override { return input_engine->SupportsNfc(identifier); } -- cgit v1.2.3