core: hid: Add nfc support to emulated controller

This commit is contained in:
german77 2022-09-24 20:36:40 -05:00
parent f6d57d7dd9
commit 8a3d22c4bd
4 changed files with 123 additions and 3 deletions

View File

@ -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),

View File

@ -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

View File

@ -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;

View File

@ -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