input_common: Add support for joycon input reports

This commit is contained in:
Narr the Reg 2022-12-20 20:27:34 -06:00
parent f7164f77d6
commit 046e95be06
8 changed files with 798 additions and 100 deletions

View file

@ -66,6 +66,7 @@ DriverResult JoyconDriver::InitializeDevice() {
// Initialize HW Protocols
calibration_protocol = std::make_unique<CalibrationProtocol>(hidapi_handle);
generic_protocol = std::make_unique<GenericProtocol>(hidapi_handle);
rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
// Get fixed joycon info
generic_protocol->GetVersionNumber(version);
@ -90,6 +91,10 @@ DriverResult JoyconDriver::InitializeDevice() {
// Apply HW configuration
SetPollingMode();
// Initialize joycon poller
joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration,
right_stick_calibration, motion_calibration);
// Start pooling for data
is_connected = true;
if (!input_thread_running) {
@ -142,15 +147,40 @@ void JoyconDriver::InputThread(std::stop_token stop_token) {
void JoyconDriver::OnNewData(std::span<u8> buffer) {
const auto report_mode = static_cast<InputReport>(buffer[0]);
// Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion
// experience
switch (report_mode) {
case InputReport::STANDARD_FULL_60HZ:
ReadActiveMode(buffer);
case InputReport::NFC_IR_MODE_60HZ:
case InputReport::SIMPLE_HID_MODE: {
const auto now = std::chrono::steady_clock::now();
const auto new_delta_time = static_cast<u64>(
std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
delta_time = ((delta_time * 8) + (new_delta_time * 2)) / 10;
last_update = now;
joycon_poller->UpdateColor(color);
break;
}
default:
break;
}
const MotionStatus motion_status{
.is_enabled = motion_enabled,
.delta_time = delta_time,
.gyro_sensitivity = gyro_sensitivity,
.accelerometer_sensitivity = accelerometer_sensitivity,
};
switch (report_mode) {
case InputReport::STANDARD_FULL_60HZ:
joycon_poller->ReadActiveMode(buffer, motion_status);
break;
case InputReport::NFC_IR_MODE_60HZ:
ReadNfcIRMode(buffer);
joycon_poller->ReadNfcIRMode(buffer, motion_status);
break;
case InputReport::SIMPLE_HID_MODE:
ReadPassiveMode(buffer);
joycon_poller->ReadPassiveMode(buffer);
break;
case InputReport::SUBCMD_REPLY:
LOG_DEBUG(Input, "Unhandled command reply");
@ -164,6 +194,8 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
void JoyconDriver::SetPollingMode() {
disable_input_thread = true;
rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration);
if (motion_enabled && supported_features.motion) {
generic_protocol->EnableImu(true);
generic_protocol->SetImuConfig(gyro_sensitivity, gyro_performance,
@ -209,62 +241,6 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() {
return features;
}
void JoyconDriver::ReadActiveMode(std::span<u8> buffer) {
InputReportActive data{};
memcpy(&data, buffer.data(), sizeof(InputReportActive));
// Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion
// experience
const auto now = std::chrono::steady_clock::now();
const auto new_delta_time =
std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count();
delta_time = static_cast<u64>((delta_time * 0.8f) + (new_delta_time * 0.2));
last_update = now;
switch (device_type) {
case Joycon::ControllerType::Left:
break;
case Joycon::ControllerType::Right:
break;
case Joycon::ControllerType::Pro:
break;
case Joycon::ControllerType::Grip:
case Joycon::ControllerType::Dual:
case Joycon::ControllerType::None:
break;
}
on_battery_data(data.battery_status);
on_color_data(color);
}
void JoyconDriver::ReadPassiveMode(std::span<u8> buffer) {
InputReportPassive data{};
memcpy(&data, buffer.data(), sizeof(InputReportPassive));
switch (device_type) {
case Joycon::ControllerType::Left:
break;
case Joycon::ControllerType::Right:
break;
case Joycon::ControllerType::Pro:
break;
case Joycon::ControllerType::Grip:
case Joycon::ControllerType::Dual:
case Joycon::ControllerType::None:
break;
}
}
void JoyconDriver::ReadNfcIRMode(std::span<u8> buffer) {
// This mode is compatible with the active mode
ReadActiveMode(buffer);
if (!nfc_enabled) {
return;
}
}
bool JoyconDriver::IsInputThreadValid() const {
if (!is_connected) {
return false;
@ -302,7 +278,7 @@ DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
if (disable_input_thread) {
return DriverResult::HandleInUse;
}
return DriverResult::NotSupported;
return rumble_protocol->SendVibration(vibration);
}
DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
@ -398,6 +374,10 @@ SerialNumber JoyconDriver::GetHandleSerialNumber() const {
return handle_serial_number;
}
void JoyconDriver::SetCallbacks(const Joycon::JoyconCallbacks& callbacks) {
joycon_poller->SetCallbacks(callbacks);
}
Joycon::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type) {
std::array<std::pair<u32, Joycon::ControllerType>, 4> supported_devices{