yuzu: Add custom ringcon configuration
This commit is contained in:
parent
b2359f1527
commit
d2f9412cf1
19 changed files with 992 additions and 65 deletions
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
|
@ -190,6 +191,7 @@ void HidBus::IsExternalDeviceConnected(Kernel::HLERequestContext& ctx) {
|
|||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(is_attached);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
|
@ -217,7 +219,7 @@ void HidBus::Initialize(Kernel::HLERequestContext& ctx) {
|
|||
const auto entry_index = devices[device_index.value()].handle.internal_index;
|
||||
auto& cur_entry = hidbus_status.entries[entry_index];
|
||||
|
||||
if (bus_handle_.internal_index == 0) {
|
||||
if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) {
|
||||
MakeDevice<RingController>(bus_handle_);
|
||||
devices[device_index.value()].is_device_initializated = true;
|
||||
devices[device_index.value()].device->ActivateDevice();
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Service::HID {
|
|||
|
||||
HidbusBase::HidbusBase(KernelHelpers::ServiceContext& service_context_)
|
||||
: service_context(service_context_) {
|
||||
send_command_asyc_event = service_context.CreateEvent("hidbus:SendCommandAsycEvent");
|
||||
send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent");
|
||||
}
|
||||
HidbusBase::~HidbusBase() = default;
|
||||
|
||||
|
@ -66,7 +66,7 @@ void HidbusBase::SetTransferMemoryPointer(u8* t_mem) {
|
|||
}
|
||||
|
||||
Kernel::KReadableEvent& HidbusBase::GetSendCommandAsycEvent() const {
|
||||
return send_command_asyc_event->GetReadableEvent();
|
||||
return send_command_async_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
|
|
|
@ -165,6 +165,7 @@ protected:
|
|||
bool device_enabled{};
|
||||
bool polling_mode_enabled{};
|
||||
JoyPollingMode polling_mode = {};
|
||||
// TODO(German77): All data accessors need to be replaced with a ring lifo object
|
||||
JoyDisableSixAxisDataAccessor disable_sixaxis_data{};
|
||||
JoyEnableSixAxisDataAccessor enable_sixaxis_data{};
|
||||
ButtonOnlyPollingDataAccessor button_only_data{};
|
||||
|
@ -172,7 +173,7 @@ protected:
|
|||
u8* transfer_memory{nullptr};
|
||||
bool is_transfer_memory_set{};
|
||||
|
||||
Kernel::KEvent* send_command_asyc_event;
|
||||
Kernel::KEvent* send_command_async_event;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
|
@ -13,9 +13,7 @@ namespace Service::HID {
|
|||
RingController::RingController(Core::HID::HIDCore& hid_core_,
|
||||
KernelHelpers::ServiceContext& service_context_)
|
||||
: HidbusBase(service_context_) {
|
||||
// Use the horizontal axis of left stick for emulating input
|
||||
// There is no point on adding a frontend implementation since Ring Fit Adventure doesn't work
|
||||
input = hid_core_.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
input = hid_core_.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
RingController::~RingController() = default;
|
||||
|
@ -41,6 +39,8 @@ void RingController::OnUpdate() {
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Increment multitasking counters from motion and sensor data
|
||||
|
||||
switch (polling_mode) {
|
||||
case JoyPollingMode::SixAxisSensorEnable: {
|
||||
enable_sixaxis_data.header.total_entries = 10;
|
||||
|
@ -74,9 +74,8 @@ RingController::RingConData RingController::GetSensorValue() const {
|
|||
.data = 0,
|
||||
};
|
||||
|
||||
const f32 stick_value = static_cast<f32>(input->GetSticks().left.x) / 32767.0f;
|
||||
|
||||
ringcon_sensor_value.data = static_cast<s16>(stick_value * range) + idle_value;
|
||||
const f32 force_value = input->GetRingSensorForce().force * range;
|
||||
ringcon_sensor_value.data = static_cast<s16>(force_value) + idle_value;
|
||||
|
||||
return ringcon_sensor_value;
|
||||
}
|
||||
|
@ -105,6 +104,8 @@ std::vector<u8> RingController::GetReply() const {
|
|||
return GetReadRepCountReply();
|
||||
case RingConCommands::ReadTotalPushCount:
|
||||
return GetReadTotalPushCountReply();
|
||||
case RingConCommands::ResetRepCount:
|
||||
return GetResetRepCountReply();
|
||||
case RingConCommands::SaveCalData:
|
||||
return GetSaveDataReply();
|
||||
default:
|
||||
|
@ -119,36 +120,9 @@ bool RingController::SetCommand(const std::vector<u8>& data) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// There must be a better way to do this
|
||||
const u32 command_id =
|
||||
u32{data[0]} + (u32{data[1]} << 8) + (u32{data[2]} << 16) + (u32{data[3]} << 24);
|
||||
static constexpr std::array supported_commands = {
|
||||
RingConCommands::GetFirmwareVersion,
|
||||
RingConCommands::ReadId,
|
||||
RingConCommands::c20105,
|
||||
RingConCommands::ReadUnkCal,
|
||||
RingConCommands::ReadFactoryCal,
|
||||
RingConCommands::ReadUserCal,
|
||||
RingConCommands::ReadRepCount,
|
||||
RingConCommands::ReadTotalPushCount,
|
||||
RingConCommands::SaveCalData,
|
||||
};
|
||||
std::memcpy(&command, data.data(), sizeof(RingConCommands));
|
||||
|
||||
for (RingConCommands cmd : supported_commands) {
|
||||
if (command_id == static_cast<u32>(cmd)) {
|
||||
return ExcecuteCommand(cmd, data);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Command not implemented {}", command_id);
|
||||
command = RingConCommands::Error;
|
||||
// Signal a reply to avoid softlocking
|
||||
send_command_asyc_event->GetWritableEvent().Signal();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RingController::ExcecuteCommand(RingConCommands cmd, const std::vector<u8>& data) {
|
||||
switch (cmd) {
|
||||
switch (command) {
|
||||
case RingConCommands::GetFirmwareVersion:
|
||||
case RingConCommands::ReadId:
|
||||
case RingConCommands::c20105:
|
||||
|
@ -158,23 +132,27 @@ bool RingController::ExcecuteCommand(RingConCommands cmd, const std::vector<u8>&
|
|||
case RingConCommands::ReadRepCount:
|
||||
case RingConCommands::ReadTotalPushCount:
|
||||
ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
|
||||
command = cmd;
|
||||
send_command_asyc_event->GetWritableEvent().Signal();
|
||||
send_command_async_event->GetWritableEvent().Signal();
|
||||
return true;
|
||||
case RingConCommands::ResetRepCount:
|
||||
ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
|
||||
total_rep_count = 0;
|
||||
send_command_async_event->GetWritableEvent().Signal();
|
||||
return true;
|
||||
case RingConCommands::SaveCalData: {
|
||||
ASSERT_MSG(data.size() == 0x14, "data.size is not 0x14 bytes");
|
||||
|
||||
SaveCalData save_info{};
|
||||
std::memcpy(&save_info, &data, sizeof(SaveCalData));
|
||||
std::memcpy(&save_info, data.data(), sizeof(SaveCalData));
|
||||
user_calibration = save_info.calibration;
|
||||
|
||||
command = cmd;
|
||||
send_command_asyc_event->GetWritableEvent().Signal();
|
||||
send_command_async_event->GetWritableEvent().Signal();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Service_HID, "Command not implemented {}", cmd);
|
||||
LOG_ERROR(Service_HID, "Command not implemented {}", command);
|
||||
command = RingConCommands::Error;
|
||||
// Signal a reply to avoid softlocking the game
|
||||
send_command_async_event->GetWritableEvent().Signal();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -240,27 +218,29 @@ std::vector<u8> RingController::GetReadUserCalReply() const {
|
|||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadRepCountReply() const {
|
||||
// The values are hardcoded from a real joycon
|
||||
const GetThreeByteReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.data = {30, 0, 0},
|
||||
.crc = GetCrcValue({30, 0, 0, 0}),
|
||||
.data = {total_rep_count, 0, 0},
|
||||
.crc = GetCrcValue({total_rep_count, 0, 0, 0}),
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadTotalPushCountReply() const {
|
||||
// The values are hardcoded from a real joycon
|
||||
const GetThreeByteReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.data = {30, 0, 0},
|
||||
.crc = GetCrcValue({30, 0, 0, 0}),
|
||||
.data = {total_push_count, 0, 0},
|
||||
.crc = GetCrcValue({total_push_count, 0, 0, 0}),
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetResetRepCountReply() const {
|
||||
return GetReadRepCountReply();
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetSaveDataReply() const {
|
||||
const StatusReply reply{
|
||||
.status = DataValid::Valid,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "core/hle/service/hid/hidbus/hidbus_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
class EmulatedDevices;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
|
@ -43,6 +43,7 @@ private:
|
|||
static constexpr s16 idle_deadzone = 120;
|
||||
static constexpr s16 range = 2500;
|
||||
|
||||
// Most missing command names are leftovers from other firmware versions
|
||||
enum class RingConCommands : u32 {
|
||||
GetFirmwareVersion = 0x00020000,
|
||||
ReadId = 0x00020100,
|
||||
|
@ -60,10 +61,10 @@ private:
|
|||
ReadUserCal = 0x00021A04,
|
||||
ReadRepCount = 0x00023104,
|
||||
ReadTotalPushCount = 0x00023204,
|
||||
Unknown9 = 0x04013104,
|
||||
Unknown10 = 0x04011104,
|
||||
Unknown11 = 0x04011204,
|
||||
Unknown12 = 0x04011304,
|
||||
ResetRepCount = 0x04013104,
|
||||
Unknown8 = 0x04011104,
|
||||
Unknown9 = 0x04011204,
|
||||
Unknown10 = 0x04011304,
|
||||
SaveCalData = 0x10011A04,
|
||||
Error = 0xFFFFFFFF,
|
||||
};
|
||||
|
@ -180,9 +181,6 @@ private:
|
|||
};
|
||||
static_assert(sizeof(RingConData) == 0x8, "RingConData is an invalid size");
|
||||
|
||||
// Executes the command requested
|
||||
bool ExcecuteCommand(RingConCommands cmd, const std::vector<u8>& data);
|
||||
|
||||
// Returns RingConData struct with pressure sensor values
|
||||
RingConData GetSensorValue() const;
|
||||
|
||||
|
@ -204,12 +202,15 @@ private:
|
|||
// Returns 20 byte reply with user calibration values
|
||||
std::vector<u8> GetReadUserCalReply() const;
|
||||
|
||||
// (STUBBED) Returns 8 byte reply
|
||||
// Returns 8 byte reply
|
||||
std::vector<u8> GetReadRepCountReply() const;
|
||||
|
||||
// (STUBBED) Returns 8 byte reply
|
||||
// Returns 8 byte reply
|
||||
std::vector<u8> GetReadTotalPushCountReply() const;
|
||||
|
||||
// Returns 8 byte reply
|
||||
std::vector<u8> GetResetRepCountReply() const;
|
||||
|
||||
// Returns 4 byte save data reply
|
||||
std::vector<u8> GetSaveDataReply() const;
|
||||
|
||||
|
@ -225,6 +226,12 @@ private:
|
|||
|
||||
RingConCommands command{RingConCommands::Error};
|
||||
|
||||
// These counters are used in multitasking mode while the switch is sleeping
|
||||
// Total steps taken
|
||||
u8 total_rep_count = 0;
|
||||
// Total times the ring was pushed
|
||||
u8 total_push_count = 0;
|
||||
|
||||
const u8 device_id = 0x20;
|
||||
const FirmwareVersion version = {
|
||||
.sub = 0x0,
|
||||
|
@ -242,6 +249,6 @@ private:
|
|||
.zero = {.value = idle_value, .crc = 225},
|
||||
};
|
||||
|
||||
Core::HID::EmulatedController* input;
|
||||
Core::HID::EmulatedDevices* input;
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue