summaryrefslogtreecommitdiffstats
path: root/src/core/hid
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hid')
-rw-r--r--src/core/hid/emulated_controller.cpp144
-rw-r--r--src/core/hid/emulated_controller.h39
-rw-r--r--src/core/hid/input_converter.cpp22
-rw-r--r--src/core/hid/input_converter.h8
-rw-r--r--src/core/hid/irs_types.h20
5 files changed, 165 insertions, 68 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 01c43be93..ec1364452 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -93,7 +93,7 @@ void EmulatedController::ReloadFromSettings() {
.body = GetNpadColor(player.body_color_left),
.button = GetNpadColor(player.button_color_left),
};
- controller.colors_state.left = {
+ controller.colors_state.right = {
.body = GetNpadColor(player.body_color_right),
.button = GetNpadColor(player.button_color_right),
};
@@ -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<Common::Input::InputDevice>);
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(),
Common::Input::CreateDevice<Common::Input::OutputDevice>);
@@ -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;
@@ -935,14 +970,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
Common::Input::VibrationError::None;
}
-bool EmulatedController::TestVibration(std::size_t device_index) {
- if (device_index >= output_devices.size()) {
- return false;
- }
- if (!output_devices[device_index]) {
- return false;
- }
-
+bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
const auto player_index = NpadIdTypeToIndex(npad_id_type);
const auto& player = Settings::values.players.GetValue()[player_index];
@@ -950,37 +978,27 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
return false;
}
- const Common::Input::VibrationStatus test_vibration = {
- .low_amplitude = 0.001f,
- .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency,
- .high_amplitude = 0.001f,
- .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency,
- .type = Common::Input::VibrationAmplificationType::Test,
- };
-
- const Common::Input::VibrationStatus zero_vibration = {
- .low_amplitude = DEFAULT_VIBRATION_VALUE.low_amplitude,
- .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency,
- .high_amplitude = DEFAULT_VIBRATION_VALUE.high_amplitude,
- .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency,
- .type = Common::Input::VibrationAmplificationType::Test,
- };
-
- // Send a slight vibration to test for rumble support
- output_devices[device_index]->SetVibration(test_vibration);
+ if (device_index >= output_devices.size()) {
+ return false;
+ }
- // Wait for about 15ms to ensure the controller is ready for the stop command
- std::this_thread::sleep_for(std::chrono::milliseconds(15));
+ if (!output_devices[device_index]) {
+ return false;
+ }
- // Stop any vibration and return the result
- return output_devices[device_index]->SetVibration(zero_vibration) ==
- Common::Input::VibrationError::None;
+ return output_devices[device_index]->IsVibrationEnabled();
}
bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
LOG_INFO(Service_HID, "Set polling mode {}", polling_mode);
auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
- return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None;
+ auto& nfc_output_device = output_devices[3];
+
+ const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
+ const auto mapped_nfc_result = output_device->SetPollingMode(polling_mode);
+
+ return virtual_nfc_result == Common::Input::PollingError::None ||
+ mapped_nfc_result == Common::Input::PollingError::None;
}
bool EmulatedController::SetCameraFormat(
@@ -1000,6 +1018,33 @@ 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:
+ case NpadStyleIndex::Handheld:
+ 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() {
for (auto& device : output_devices) {
if (!device) {
@@ -1091,27 +1136,27 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
switch (type) {
case NpadStyleIndex::ProController:
- return supported_style_tag.fullkey;
+ return supported_style_tag.fullkey.As<bool>();
case NpadStyleIndex::Handheld:
- return supported_style_tag.handheld;
+ return supported_style_tag.handheld.As<bool>();
case NpadStyleIndex::JoyconDual:
- return supported_style_tag.joycon_dual;
+ return supported_style_tag.joycon_dual.As<bool>();
case NpadStyleIndex::JoyconLeft:
- return supported_style_tag.joycon_left;
+ return supported_style_tag.joycon_left.As<bool>();
case NpadStyleIndex::JoyconRight:
- return supported_style_tag.joycon_right;
+ return supported_style_tag.joycon_right.As<bool>();
case NpadStyleIndex::GameCube:
- return supported_style_tag.gamecube;
+ return supported_style_tag.gamecube.As<bool>();
case NpadStyleIndex::Pokeball:
- return supported_style_tag.palma;
+ return supported_style_tag.palma.As<bool>();
case NpadStyleIndex::NES:
- return supported_style_tag.lark;
+ return supported_style_tag.lark.As<bool>();
case NpadStyleIndex::SNES:
- return supported_style_tag.lucia;
+ return supported_style_tag.lucia.As<bool>();
case NpadStyleIndex::N64:
- return supported_style_tag.lagoon;
+ return supported_style_tag.lagoon.As<bool>();
case NpadStyleIndex::SegaGenesis:
- return supported_style_tag.lager;
+ return supported_style_tag.lager.As<bool>();
default:
return false;
}
@@ -1167,12 +1212,6 @@ bool EmulatedController::IsConnected(bool get_temporary_value) const {
return is_connected;
}
-bool EmulatedController::IsVibrationEnabled() const {
- const auto player_index = NpadIdTypeToIndex(npad_id_type);
- const auto& player = Settings::values.players.GetValue()[player_index];
- return player.vibration_enabled;
-}
-
NpadIdType EmulatedController::GetNpadIdType() const {
std::scoped_lock lock{mutex};
return npad_id_type;
@@ -1363,6 +1402,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<u8>((color >> 16) & 0xFF),
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index c3aa8f9d3..d004ca56a 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<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
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 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 BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
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 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 BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
using CameraValues = Common::Input::CameraStatus;
+using NfcValues = Common::Input::NfcStatus;
using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
struct AnalogSticks {
@@ -80,6 +83,11 @@ struct CameraState {
std::size_t sample{};
};
+struct NfcState {
+ Common::Input::NfcState state{};
+ std::vector<u8> 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,
@@ -195,9 +206,6 @@ public:
*/
bool IsConnected(bool get_temporary_value = false) const;
- /// Returns true if vibration is enabled
- bool IsVibrationEnabled() const;
-
/// Removes all callbacks created from input devices
void UnloadInput();
@@ -315,6 +323,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
@@ -325,7 +336,7 @@ public:
* Sends a small vibration to the output device
* @return true if SetVibration was successfull
*/
- bool TestVibration(std::size_t device_index);
+ bool IsVibrationEnabled(std::size_t device_index);
/**
* Sets the desired data to be polled from a controller
@@ -341,6 +352,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<u8>& data);
+
/// Returns the led pattern corresponding to this emulated controller
LedPattern GetLedPattern() const;
@@ -425,6 +442,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
* @return NpadColor in rgba format
@@ -458,6 +481,7 @@ private:
TriggerParams trigger_params;
BatteryParams battery_params;
CameraParams camera_params;
+ NfcParams nfc_params;
OutputParams output_params;
ButtonDevices button_devices;
@@ -466,6 +490,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..5d8b75b50 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -277,7 +277,10 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu
Common::Input::CameraStatus camera{};
switch (callback.type) {
case Common::Input::InputType::IrSensor:
- camera = callback.camera_status;
+ camera = {
+ .format = callback.camera_status,
+ .data = callback.raw_data,
+ };
break;
default:
LOG_ERROR(Input, "Conversion from type {} to camera not implemented", callback.type);
@@ -287,6 +290,23 @@ 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 = {
+ .state = callback.nfc_status,
+ .data = callback.raw_data,
+ };
+ 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
@@ -85,6 +85,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
* @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f.
diff --git a/src/core/hid/irs_types.h b/src/core/hid/irs_types.h
index 88c5b016d..0d1bfe53f 100644
--- a/src/core/hid/irs_types.h
+++ b/src/core/hid/irs_types.h
@@ -14,7 +14,7 @@ enum class CameraAmbientNoiseLevel : u32 {
Low,
Medium,
High,
- Unkown3, // This level can't be reached
+ Unknown3, // This level can't be reached
};
// This is nn::irsensor::CameraLightTarget
@@ -75,9 +75,9 @@ enum class IrCameraStatus : u32 {
enum class IrCameraInternalStatus : u32 {
Stopped,
FirmwareUpdateNeeded,
- Unkown2,
- Unkown3,
- Unkown4,
+ Unknown2,
+ Unknown3,
+ Unknown4,
FirmwareVersionRequested,
FirmwareVersionIsInvalid,
Ready,
@@ -121,20 +121,20 @@ enum class IrSensorFunctionLevel : u8 {
// This is nn::irsensor::MomentProcessorPreprocess
enum class MomentProcessorPreprocess : u32 {
- Unkown0,
- Unkown1,
+ Unknown0,
+ Unknown1,
};
// This is nn::irsensor::PackedMomentProcessorPreprocess
enum class PackedMomentProcessorPreprocess : u8 {
- Unkown0,
- Unkown1,
+ Unknown0,
+ Unknown1,
};
// This is nn::irsensor::PointingStatus
enum class PointingStatus : u32 {
- Unkown0,
- Unkown1,
+ Unknown0,
+ Unknown1,
};
struct IrsRect {