core: hid: Add nfc support to emulated controller
This commit is contained in:
		| @@ -131,13 +131,16 @@ void EmulatedController::LoadDevices() { | |||||||
|     battery_params[RightIndex].Set("battery", true); |     battery_params[RightIndex].Set("battery", true); | ||||||
|  |  | ||||||
|     camera_params = Common::ParamPackage{"engine:camera,camera:1"}; |     camera_params = Common::ParamPackage{"engine:camera,camera:1"}; | ||||||
|  |     nfc_params = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; | ||||||
|  |  | ||||||
|     output_params[LeftIndex] = left_joycon; |     output_params[LeftIndex] = left_joycon; | ||||||
|     output_params[RightIndex] = right_joycon; |     output_params[RightIndex] = right_joycon; | ||||||
|     output_params[2] = camera_params; |     output_params[2] = camera_params; | ||||||
|  |     output_params[3] = nfc_params; | ||||||
|     output_params[LeftIndex].Set("output", true); |     output_params[LeftIndex].Set("output", true); | ||||||
|     output_params[RightIndex].Set("output", true); |     output_params[RightIndex].Set("output", true); | ||||||
|     output_params[2].Set("output", true); |     output_params[2].Set("output", true); | ||||||
|  |     output_params[3].Set("output", true); | ||||||
|  |  | ||||||
|     LoadTASParams(); |     LoadTASParams(); | ||||||
|  |  | ||||||
| @@ -155,6 +158,7 @@ void EmulatedController::LoadDevices() { | |||||||
|     std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), |     std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), | ||||||
|                    Common::Input::CreateDevice<Common::Input::InputDevice>); |                    Common::Input::CreateDevice<Common::Input::InputDevice>); | ||||||
|     camera_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(camera_params); |     camera_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(camera_params); | ||||||
|  |     nfc_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(nfc_params); | ||||||
|     std::transform(output_params.begin(), output_params.end(), output_devices.begin(), |     std::transform(output_params.begin(), output_params.end(), output_devices.begin(), | ||||||
|                    Common::Input::CreateDevice<Common::Input::OutputDevice>); |                    Common::Input::CreateDevice<Common::Input::OutputDevice>); | ||||||
|  |  | ||||||
| @@ -284,6 +288,16 @@ void EmulatedController::ReloadInput() { | |||||||
|         camera_devices->ForceUpdate(); |         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 |     // Use a common UUID for TAS | ||||||
|     static constexpr Common::UUID TAS_UUID = Common::UUID{ |     static constexpr Common::UUID TAS_UUID = Common::UUID{ | ||||||
|         {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; |         {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) { |     for (auto& stick : tas_stick_devices) { | ||||||
|         stick.reset(); |         stick.reset(); | ||||||
|     } |     } | ||||||
|  |     camera_devices.reset(); | ||||||
|  |     nfc_devices.reset(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmulatedController::EnableConfiguration() { | void EmulatedController::EnableConfiguration() { | ||||||
| @@ -903,6 +919,25 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback | |||||||
|     TriggerOnChange(ControllerTriggerType::IrSensor, true); |     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) { | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { | ||||||
|     if (device_index >= output_devices.size()) { |     if (device_index >= output_devices.size()) { | ||||||
|         return false; |         return false; | ||||||
| @@ -980,6 +1015,10 @@ bool EmulatedController::TestVibration(std::size_t device_index) { | |||||||
| bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { | bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { | ||||||
|     LOG_INFO(Service_HID, "Set polling mode {}", polling_mode); |     LOG_INFO(Service_HID, "Set polling mode {}", polling_mode); | ||||||
|     auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |     auto& output_device = output_devices[static_cast<std::size_t>(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; |     return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1000,6 +1039,32 @@ bool EmulatedController::SetCameraFormat( | |||||||
|                camera_format)) == Common::Input::CameraError::None; |                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<u8>& data) { | ||||||
|  |     auto& nfc_output_device = output_devices[3]; | ||||||
|  |  | ||||||
|  |     return nfc_output_device->WriteNfcData(data) == Common::Input::NfcState::Success; | ||||||
|  | } | ||||||
|  |  | ||||||
| void EmulatedController::SetLedPattern() { | void EmulatedController::SetLedPattern() { | ||||||
|     for (auto& device : output_devices) { |     for (auto& device : output_devices) { | ||||||
|         if (!device) { |         if (!device) { | ||||||
| @@ -1363,6 +1428,11 @@ const CameraState& EmulatedController::GetCamera() const { | |||||||
|     return controller.camera_state; |     return controller.camera_state; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const NfcState& EmulatedController::GetNfc() const { | ||||||
|  |     std::scoped_lock lock{mutex}; | ||||||
|  |     return controller.nfc_state; | ||||||
|  | } | ||||||
|  |  | ||||||
| NpadColor EmulatedController::GetNpadColor(u32 color) { | NpadColor EmulatedController::GetNpadColor(u32 color) { | ||||||
|     return { |     return { | ||||||
|         .r = static_cast<u8>((color >> 16) & 0xFF), |         .r = static_cast<u8>((color >> 16) & 0xFF), | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ | |||||||
|  |  | ||||||
| namespace Core::HID { | namespace Core::HID { | ||||||
| const std::size_t max_emulated_controllers = 2; | 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 { | struct ControllerMotionInfo { | ||||||
|     Common::Input::MotionStatus raw_status{}; |     Common::Input::MotionStatus raw_status{}; | ||||||
|     MotionInput emulated{}; |     MotionInput emulated{}; | ||||||
| @@ -37,7 +37,8 @@ using TriggerDevices = | |||||||
| using BatteryDevices = | using BatteryDevices = | ||||||
|     std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; |     std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; | ||||||
| using CameraDevices = std::unique_ptr<Common::Input::InputDevice>; | using CameraDevices = std::unique_ptr<Common::Input::InputDevice>; | ||||||
| using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices>; | using NfcDevices = std::unique_ptr<Common::Input::InputDevice>; | ||||||
|  | using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>; | ||||||
|  |  | ||||||
| using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; | using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; | ||||||
| using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; | using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; | ||||||
| @@ -45,7 +46,8 @@ using ControllerMotionParams = std::array<Common::ParamPackage, Settings::Native | |||||||
| using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; | using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; | ||||||
| using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>; | using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>; | ||||||
| using CameraParams = Common::ParamPackage; | using CameraParams = Common::ParamPackage; | ||||||
| using OutputParams = std::array<Common::ParamPackage, output_devices>; | using NfcParams = Common::ParamPackage; | ||||||
|  | using OutputParams = std::array<Common::ParamPackage, output_devices_size>; | ||||||
|  |  | ||||||
| using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>; | using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>; | ||||||
| using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>; | using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>; | ||||||
| @@ -55,6 +57,7 @@ using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::Native | |||||||
| using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>; | using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>; | ||||||
| using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>; | using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>; | ||||||
| using CameraValues = Common::Input::CameraStatus; | using CameraValues = Common::Input::CameraStatus; | ||||||
|  | using NfcValues = Common::Input::NfcStatus; | ||||||
| using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>; | using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>; | ||||||
|  |  | ||||||
| struct AnalogSticks { | struct AnalogSticks { | ||||||
| @@ -80,6 +83,11 @@ struct CameraState { | |||||||
|     std::size_t sample{}; |     std::size_t sample{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct NfcState { | ||||||
|  |     Common::Input::NfcState state{}; | ||||||
|  |     std::vector<u8> data{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct ControllerMotion { | struct ControllerMotion { | ||||||
|     Common::Vec3f accel{}; |     Common::Vec3f accel{}; | ||||||
|     Common::Vec3f gyro{}; |     Common::Vec3f gyro{}; | ||||||
| @@ -107,6 +115,7 @@ struct ControllerStatus { | |||||||
|     BatteryValues battery_values{}; |     BatteryValues battery_values{}; | ||||||
|     VibrationValues vibration_values{}; |     VibrationValues vibration_values{}; | ||||||
|     CameraValues camera_values{}; |     CameraValues camera_values{}; | ||||||
|  |     NfcValues nfc_values{}; | ||||||
|  |  | ||||||
|     // Data for HID serices |     // Data for HID serices | ||||||
|     HomeButtonState home_button_state{}; |     HomeButtonState home_button_state{}; | ||||||
| @@ -119,6 +128,7 @@ struct ControllerStatus { | |||||||
|     ControllerColors colors_state{}; |     ControllerColors colors_state{}; | ||||||
|     BatteryLevelState battery_state{}; |     BatteryLevelState battery_state{}; | ||||||
|     CameraState camera_state{}; |     CameraState camera_state{}; | ||||||
|  |     NfcState nfc_state{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum class ControllerTriggerType { | enum class ControllerTriggerType { | ||||||
| @@ -130,6 +140,7 @@ enum class ControllerTriggerType { | |||||||
|     Battery, |     Battery, | ||||||
|     Vibration, |     Vibration, | ||||||
|     IrSensor, |     IrSensor, | ||||||
|  |     Nfc, | ||||||
|     Connected, |     Connected, | ||||||
|     Disconnected, |     Disconnected, | ||||||
|     Type, |     Type, | ||||||
| @@ -315,6 +326,9 @@ public: | |||||||
|     /// Returns the latest camera status from the controller |     /// Returns the latest camera status from the controller | ||||||
|     const CameraState& GetCamera() const; |     const CameraState& GetCamera() const; | ||||||
|  |  | ||||||
|  |     /// Returns the latest ntag status from the controller | ||||||
|  |     const NfcState& GetNfc() const; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Sends a specific vibration to the output device |      * Sends a specific vibration to the output device | ||||||
|      * @return true if vibration had no errors |      * @return true if vibration had no errors | ||||||
| @@ -341,6 +355,12 @@ public: | |||||||
|      */ |      */ | ||||||
|     bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format); |     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<u8>& data); | ||||||
|  |  | ||||||
|     /// Returns the led pattern corresponding to this emulated controller |     /// Returns the led pattern corresponding to this emulated controller | ||||||
|     LedPattern GetLedPattern() const; |     LedPattern GetLedPattern() const; | ||||||
|  |  | ||||||
| @@ -424,6 +444,12 @@ private: | |||||||
|      */ |      */ | ||||||
|     void SetCamera(const Common::Input::CallbackStatus& callback); |     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 |      * Converts a color format from bgra to rgba | ||||||
|      * @param color in bgra format |      * @param color in bgra format | ||||||
| @@ -458,6 +484,7 @@ private: | |||||||
|     TriggerParams trigger_params; |     TriggerParams trigger_params; | ||||||
|     BatteryParams battery_params; |     BatteryParams battery_params; | ||||||
|     CameraParams camera_params; |     CameraParams camera_params; | ||||||
|  |     NfcParams nfc_params; | ||||||
|     OutputParams output_params; |     OutputParams output_params; | ||||||
|  |  | ||||||
|     ButtonDevices button_devices; |     ButtonDevices button_devices; | ||||||
| @@ -466,6 +493,7 @@ private: | |||||||
|     TriggerDevices trigger_devices; |     TriggerDevices trigger_devices; | ||||||
|     BatteryDevices battery_devices; |     BatteryDevices battery_devices; | ||||||
|     CameraDevices camera_devices; |     CameraDevices camera_devices; | ||||||
|  |     NfcDevices nfc_devices; | ||||||
|     OutputDevices output_devices; |     OutputDevices output_devices; | ||||||
|  |  | ||||||
|     // TAS related variables |     // TAS related variables | ||||||
|   | |||||||
| @@ -287,6 +287,20 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu | |||||||
|     return camera; |     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) { | void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { | ||||||
|     const auto& properties = analog.properties; |     const auto& properties = analog.properties; | ||||||
|     float& raw_value = analog.raw_value; |     float& raw_value = analog.raw_value; | ||||||
|   | |||||||
| @@ -84,6 +84,14 @@ Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatu | |||||||
|  */ |  */ | ||||||
| Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback); | 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 |  * Converts raw analog data into a valid analog value | ||||||
|  * @param analog An analog object containing raw data and properties |  * @param analog An analog object containing raw data and properties | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user