diff options
Diffstat (limited to 'src/input_common')
18 files changed, 532 insertions, 343 deletions
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index ecb3e9dc2..d09ff178b 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "common/param_package.h" | 8 | #include "common/param_package.h" |
| 9 | #include "common/polyfill_thread.h" | ||
| 9 | #include "common/settings_input.h" | 10 | #include "common/settings_input.h" |
| 10 | #include "common/thread.h" | 11 | #include "common/thread.h" |
| 11 | #include "input_common/drivers/gc_adapter.h" | 12 | #include "input_common/drivers/gc_adapter.h" |
| @@ -217,8 +218,7 @@ void GCAdapter::AdapterScanThread(std::stop_token stop_token) { | |||
| 217 | Common::SetCurrentThreadName("ScanGCAdapter"); | 218 | Common::SetCurrentThreadName("ScanGCAdapter"); |
| 218 | usb_adapter_handle = nullptr; | 219 | usb_adapter_handle = nullptr; |
| 219 | pads = {}; | 220 | pads = {}; |
| 220 | while (!stop_token.stop_requested() && !Setup()) { | 221 | while (!Setup() && Common::StoppableTimedWait(stop_token, std::chrono::seconds{2})) { |
| 221 | std::this_thread::sleep_for(std::chrono::seconds(2)); | ||
| 222 | } | 222 | } |
| 223 | } | 223 | } |
| 224 | 224 | ||
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index 40cda400d..4fcfb4510 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/param_package.h" | 6 | #include "common/param_package.h" |
| 7 | #include "common/polyfill_ranges.h" | 7 | #include "common/polyfill_ranges.h" |
| 8 | #include "common/polyfill_thread.h" | ||
| 8 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 9 | #include "common/thread.h" | 10 | #include "common/thread.h" |
| 10 | #include "input_common/drivers/joycon.h" | 11 | #include "input_common/drivers/joycon.h" |
| @@ -67,7 +68,8 @@ void Joycons::Setup() { | |||
| 67 | void Joycons::ScanThread(std::stop_token stop_token) { | 68 | void Joycons::ScanThread(std::stop_token stop_token) { |
| 68 | constexpr u16 nintendo_vendor_id = 0x057e; | 69 | constexpr u16 nintendo_vendor_id = 0x057e; |
| 69 | Common::SetCurrentThreadName("JoyconScanThread"); | 70 | Common::SetCurrentThreadName("JoyconScanThread"); |
| 70 | while (!stop_token.stop_requested()) { | 71 | |
| 72 | do { | ||
| 71 | SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); | 73 | SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); |
| 72 | SDL_hid_device_info* cur_dev = devs; | 74 | SDL_hid_device_info* cur_dev = devs; |
| 73 | 75 | ||
| @@ -81,8 +83,7 @@ void Joycons::ScanThread(std::stop_token stop_token) { | |||
| 81 | } | 83 | } |
| 82 | 84 | ||
| 83 | SDL_hid_free_enumeration(devs); | 85 | SDL_hid_free_enumeration(devs); |
| 84 | std::this_thread::sleep_for(std::chrono::seconds(5)); | 86 | } while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5})); |
| 85 | } | ||
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { | 89 | bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { |
| @@ -667,12 +668,10 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { | |||
| 667 | return "Right Joycon"; | 668 | return "Right Joycon"; |
| 668 | case Joycon::ControllerType::Pro: | 669 | case Joycon::ControllerType::Pro: |
| 669 | return "Pro Controller"; | 670 | return "Pro Controller"; |
| 670 | case Joycon::ControllerType::Grip: | ||
| 671 | return "Grip Controller"; | ||
| 672 | case Joycon::ControllerType::Dual: | 671 | case Joycon::ControllerType::Dual: |
| 673 | return "Dual Joycon"; | 672 | return "Dual Joycon"; |
| 674 | default: | 673 | default: |
| 675 | return "Unknown Joycon"; | 674 | return "Unknown Switch Controller"; |
| 676 | } | 675 | } |
| 677 | } | 676 | } |
| 678 | } // namespace InputCommon | 677 | } // namespace InputCommon |
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index 316d383d8..2149ab7fd 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h | |||
| @@ -15,7 +15,7 @@ using SerialNumber = std::array<u8, 15>; | |||
| 15 | struct Battery; | 15 | struct Battery; |
| 16 | struct Color; | 16 | struct Color; |
| 17 | struct MotionData; | 17 | struct MotionData; |
| 18 | enum class ControllerType; | 18 | enum class ControllerType : u8; |
| 19 | enum class DriverResult; | 19 | enum class DriverResult; |
| 20 | enum class IrsResolution; | 20 | enum class IrsResolution; |
| 21 | class JoyconDriver; | 21 | class JoyconDriver; |
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 4159e5717..8f94c9f45 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp | |||
| @@ -86,6 +86,7 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 86 | 86 | ||
| 87 | // Get fixed joycon info | 87 | // Get fixed joycon info |
| 88 | generic_protocol->GetVersionNumber(version); | 88 | generic_protocol->GetVersionNumber(version); |
| 89 | generic_protocol->SetLowPowerMode(false); | ||
| 89 | generic_protocol->GetColor(color); | 90 | generic_protocol->GetColor(color); |
| 90 | if (handle_device_type == ControllerType::Pro) { | 91 | if (handle_device_type == ControllerType::Pro) { |
| 91 | // Some 3rd party controllers aren't pro controllers | 92 | // Some 3rd party controllers aren't pro controllers |
| @@ -161,14 +162,14 @@ void JoyconDriver::InputThread(std::stop_token stop_token) { | |||
| 161 | } | 162 | } |
| 162 | 163 | ||
| 163 | void JoyconDriver::OnNewData(std::span<u8> buffer) { | 164 | void JoyconDriver::OnNewData(std::span<u8> buffer) { |
| 164 | const auto report_mode = static_cast<InputReport>(buffer[0]); | 165 | const auto report_mode = static_cast<ReportMode>(buffer[0]); |
| 165 | 166 | ||
| 166 | // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion | 167 | // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion |
| 167 | // experience | 168 | // experience |
| 168 | switch (report_mode) { | 169 | switch (report_mode) { |
| 169 | case InputReport::STANDARD_FULL_60HZ: | 170 | case ReportMode::STANDARD_FULL_60HZ: |
| 170 | case InputReport::NFC_IR_MODE_60HZ: | 171 | case ReportMode::NFC_IR_MODE_60HZ: |
| 171 | case InputReport::SIMPLE_HID_MODE: { | 172 | case ReportMode::SIMPLE_HID_MODE: { |
| 172 | const auto now = std::chrono::steady_clock::now(); | 173 | const auto now = std::chrono::steady_clock::now(); |
| 173 | const auto new_delta_time = static_cast<u64>( | 174 | const auto new_delta_time = static_cast<u64>( |
| 174 | std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count()); | 175 | std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count()); |
| @@ -189,7 +190,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 189 | }; | 190 | }; |
| 190 | 191 | ||
| 191 | // TODO: Remove this when calibration is properly loaded and not calculated | 192 | // TODO: Remove this when calibration is properly loaded and not calculated |
| 192 | if (ring_connected && report_mode == InputReport::STANDARD_FULL_60HZ) { | 193 | if (ring_connected && report_mode == ReportMode::STANDARD_FULL_60HZ) { |
| 193 | InputReportActive data{}; | 194 | InputReportActive data{}; |
| 194 | memcpy(&data, buffer.data(), sizeof(InputReportActive)); | 195 | memcpy(&data, buffer.data(), sizeof(InputReportActive)); |
| 195 | calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input); | 196 | calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input); |
| @@ -227,16 +228,16 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | switch (report_mode) { | 230 | switch (report_mode) { |
| 230 | case InputReport::STANDARD_FULL_60HZ: | 231 | case ReportMode::STANDARD_FULL_60HZ: |
| 231 | joycon_poller->ReadActiveMode(buffer, motion_status, ring_status); | 232 | joycon_poller->ReadActiveMode(buffer, motion_status, ring_status); |
| 232 | break; | 233 | break; |
| 233 | case InputReport::NFC_IR_MODE_60HZ: | 234 | case ReportMode::NFC_IR_MODE_60HZ: |
| 234 | joycon_poller->ReadNfcIRMode(buffer, motion_status); | 235 | joycon_poller->ReadNfcIRMode(buffer, motion_status); |
| 235 | break; | 236 | break; |
| 236 | case InputReport::SIMPLE_HID_MODE: | 237 | case ReportMode::SIMPLE_HID_MODE: |
| 237 | joycon_poller->ReadPassiveMode(buffer); | 238 | joycon_poller->ReadPassiveMode(buffer); |
| 238 | break; | 239 | break; |
| 239 | case InputReport::SUBCMD_REPLY: | 240 | case ReportMode::SUBCMD_REPLY: |
| 240 | LOG_DEBUG(Input, "Unhandled command reply"); | 241 | LOG_DEBUG(Input, "Unhandled command reply"); |
| 241 | break; | 242 | break; |
| 242 | default: | 243 | default: |
| @@ -324,6 +325,8 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 324 | if (result != DriverResult::Success) { | 325 | if (result != DriverResult::Success) { |
| 325 | LOG_ERROR(Input, "Error enabling active mode"); | 326 | LOG_ERROR(Input, "Error enabling active mode"); |
| 326 | } | 327 | } |
| 328 | // Switch calls this function after enabling active mode | ||
| 329 | generic_protocol->TriggersElapsed(); | ||
| 327 | 330 | ||
| 328 | disable_input_thread = false; | 331 | disable_input_thread = false; |
| 329 | return result; | 332 | return result; |
diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp index f6e7e97d5..d8f040f75 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.cpp +++ b/src/input_common/helpers/joycon_protocol/calibration.cpp | |||
| @@ -13,33 +13,33 @@ CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) | |||
| 13 | 13 | ||
| 14 | DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { | 14 | DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { |
| 15 | ScopedSetBlocking sb(this); | 15 | ScopedSetBlocking sb(this); |
| 16 | std::vector<u8> buffer; | ||
| 17 | DriverResult result{DriverResult::Success}; | 16 | DriverResult result{DriverResult::Success}; |
| 17 | JoystickLeftSpiCalibration spi_calibration{}; | ||
| 18 | bool has_user_calibration = false; | ||
| 18 | calibration = {}; | 19 | calibration = {}; |
| 19 | 20 | ||
| 20 | result = ReadSPI(CalAddr::USER_LEFT_MAGIC, sizeof(u16), buffer); | ||
| 21 | |||
| 22 | if (result == DriverResult::Success) { | 21 | if (result == DriverResult::Success) { |
| 23 | const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1; | 22 | result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration); |
| 24 | if (has_user_calibration) { | ||
| 25 | result = ReadSPI(CalAddr::USER_LEFT_DATA, 9, buffer); | ||
| 26 | } else { | ||
| 27 | result = ReadSPI(CalAddr::FACT_LEFT_DATA, 9, buffer); | ||
| 28 | } | ||
| 29 | } | 23 | } |
| 30 | 24 | ||
| 31 | if (result == DriverResult::Success) { | 25 | // Read User defined calibration |
| 32 | calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]); | 26 | if (result == DriverResult::Success && has_user_calibration) { |
| 33 | calibration.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4)); | 27 | result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration); |
| 34 | calibration.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]); | ||
| 35 | calibration.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4)); | ||
| 36 | calibration.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]); | ||
| 37 | calibration.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4)); | ||
| 38 | } | 28 | } |
| 39 | 29 | ||
| 40 | // Nintendo fix for drifting stick | 30 | // Read Factory calibration |
| 41 | // result = ReadSPI(0x60, 0x86 ,buffer, 16); | 31 | if (result == DriverResult::Success && !has_user_calibration) { |
| 42 | // calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]); | 32 | result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration); |
| 33 | } | ||
| 34 | |||
| 35 | if (result == DriverResult::Success) { | ||
| 36 | calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); | ||
| 37 | calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); | ||
| 38 | calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); | ||
| 39 | calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min); | ||
| 40 | calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max); | ||
| 41 | calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max); | ||
| 42 | } | ||
| 43 | 43 | ||
| 44 | // Set a valid default calibration if data is missing | 44 | // Set a valid default calibration if data is missing |
| 45 | ValidateCalibration(calibration); | 45 | ValidateCalibration(calibration); |
| @@ -49,33 +49,33 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration | |||
| 49 | 49 | ||
| 50 | DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { | 50 | DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { |
| 51 | ScopedSetBlocking sb(this); | 51 | ScopedSetBlocking sb(this); |
| 52 | std::vector<u8> buffer; | ||
| 53 | DriverResult result{DriverResult::Success}; | 52 | DriverResult result{DriverResult::Success}; |
| 53 | JoystickRightSpiCalibration spi_calibration{}; | ||
| 54 | bool has_user_calibration = false; | ||
| 54 | calibration = {}; | 55 | calibration = {}; |
| 55 | 56 | ||
| 56 | result = ReadSPI(CalAddr::USER_RIGHT_MAGIC, sizeof(u16), buffer); | ||
| 57 | |||
| 58 | if (result == DriverResult::Success) { | 57 | if (result == DriverResult::Success) { |
| 59 | const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1; | 58 | result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration); |
| 60 | if (has_user_calibration) { | ||
| 61 | result = ReadSPI(CalAddr::USER_RIGHT_DATA, 9, buffer); | ||
| 62 | } else { | ||
| 63 | result = ReadSPI(CalAddr::FACT_RIGHT_DATA, 9, buffer); | ||
| 64 | } | ||
| 65 | } | 59 | } |
| 66 | 60 | ||
| 67 | if (result == DriverResult::Success) { | 61 | // Read User defined calibration |
| 68 | calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]); | 62 | if (result == DriverResult::Success && has_user_calibration) { |
| 69 | calibration.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4)); | 63 | result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration); |
| 70 | calibration.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]); | 64 | } |
| 71 | calibration.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4)); | 65 | |
| 72 | calibration.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]); | 66 | // Read Factory calibration |
| 73 | calibration.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4)); | 67 | if (result == DriverResult::Success && !has_user_calibration) { |
| 68 | result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration); | ||
| 74 | } | 69 | } |
| 75 | 70 | ||
| 76 | // Nintendo fix for drifting stick | 71 | if (result == DriverResult::Success) { |
| 77 | // buffer = ReadSPI(0x60, 0x98 , 16); | 72 | calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); |
| 78 | // joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]); | 73 | calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); |
| 74 | calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); | ||
| 75 | calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min); | ||
| 76 | calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max); | ||
| 77 | calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max); | ||
| 78 | } | ||
| 79 | 79 | ||
| 80 | // Set a valid default calibration if data is missing | 80 | // Set a valid default calibration if data is missing |
| 81 | ValidateCalibration(calibration); | 81 | ValidateCalibration(calibration); |
| @@ -85,39 +85,41 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio | |||
| 85 | 85 | ||
| 86 | DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { | 86 | DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { |
| 87 | ScopedSetBlocking sb(this); | 87 | ScopedSetBlocking sb(this); |
| 88 | std::vector<u8> buffer; | ||
| 89 | DriverResult result{DriverResult::Success}; | 88 | DriverResult result{DriverResult::Success}; |
| 89 | ImuSpiCalibration spi_calibration{}; | ||
| 90 | bool has_user_calibration = false; | ||
| 90 | calibration = {}; | 91 | calibration = {}; |
| 91 | 92 | ||
| 92 | result = ReadSPI(CalAddr::USER_IMU_MAGIC, sizeof(u16), buffer); | ||
| 93 | |||
| 94 | if (result == DriverResult::Success) { | 93 | if (result == DriverResult::Success) { |
| 95 | const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1; | 94 | result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration); |
| 96 | if (has_user_calibration) { | 95 | } |
| 97 | result = ReadSPI(CalAddr::USER_IMU_DATA, sizeof(IMUCalibration), buffer); | 96 | |
| 98 | } else { | 97 | // Read User defined calibration |
| 99 | result = ReadSPI(CalAddr::FACT_IMU_DATA, sizeof(IMUCalibration), buffer); | 98 | if (result == DriverResult::Success && has_user_calibration) { |
| 100 | } | 99 | result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration); |
| 100 | } | ||
| 101 | |||
| 102 | // Read Factory calibration | ||
| 103 | if (result == DriverResult::Success && !has_user_calibration) { | ||
| 104 | result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration); | ||
| 101 | } | 105 | } |
| 102 | 106 | ||
| 103 | if (result == DriverResult::Success) { | 107 | if (result == DriverResult::Success) { |
| 104 | IMUCalibration device_calibration{}; | 108 | calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0]; |
| 105 | memcpy(&device_calibration, buffer.data(), sizeof(IMUCalibration)); | 109 | calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1]; |
| 106 | calibration.accelerometer[0].offset = device_calibration.accelerometer_offset[0]; | 110 | calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2]; |
| 107 | calibration.accelerometer[1].offset = device_calibration.accelerometer_offset[1]; | ||
| 108 | calibration.accelerometer[2].offset = device_calibration.accelerometer_offset[2]; | ||
| 109 | 111 | ||
| 110 | calibration.accelerometer[0].scale = device_calibration.accelerometer_scale[0]; | 112 | calibration.accelerometer[0].scale = spi_calibration.accelerometer_scale[0]; |
| 111 | calibration.accelerometer[1].scale = device_calibration.accelerometer_scale[1]; | 113 | calibration.accelerometer[1].scale = spi_calibration.accelerometer_scale[1]; |
| 112 | calibration.accelerometer[2].scale = device_calibration.accelerometer_scale[2]; | 114 | calibration.accelerometer[2].scale = spi_calibration.accelerometer_scale[2]; |
| 113 | 115 | ||
| 114 | calibration.gyro[0].offset = device_calibration.gyroscope_offset[0]; | 116 | calibration.gyro[0].offset = spi_calibration.gyroscope_offset[0]; |
| 115 | calibration.gyro[1].offset = device_calibration.gyroscope_offset[1]; | 117 | calibration.gyro[1].offset = spi_calibration.gyroscope_offset[1]; |
| 116 | calibration.gyro[2].offset = device_calibration.gyroscope_offset[2]; | 118 | calibration.gyro[2].offset = spi_calibration.gyroscope_offset[2]; |
| 117 | 119 | ||
| 118 | calibration.gyro[0].scale = device_calibration.gyroscope_scale[0]; | 120 | calibration.gyro[0].scale = spi_calibration.gyroscope_scale[0]; |
| 119 | calibration.gyro[1].scale = device_calibration.gyroscope_scale[1]; | 121 | calibration.gyro[1].scale = spi_calibration.gyroscope_scale[1]; |
| 120 | calibration.gyro[2].scale = device_calibration.gyroscope_scale[2]; | 122 | calibration.gyro[2].scale = spi_calibration.gyroscope_scale[2]; |
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | ValidateCalibration(calibration); | 125 | ValidateCalibration(calibration); |
| @@ -127,10 +129,12 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati | |||
| 127 | 129 | ||
| 128 | DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, | 130 | DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, |
| 129 | s16 current_value) { | 131 | s16 current_value) { |
| 132 | constexpr s16 DefaultRingRange{800}; | ||
| 133 | |||
| 130 | // TODO: Get default calibration form ring itself | 134 | // TODO: Get default calibration form ring itself |
| 131 | if (ring_data_max == 0 && ring_data_min == 0) { | 135 | if (ring_data_max == 0 && ring_data_min == 0) { |
| 132 | ring_data_max = current_value + 800; | 136 | ring_data_max = current_value + DefaultRingRange; |
| 133 | ring_data_min = current_value - 800; | 137 | ring_data_min = current_value - DefaultRingRange; |
| 134 | ring_data_default = current_value; | 138 | ring_data_default = current_value; |
| 135 | } | 139 | } |
| 136 | ring_data_max = std::max(ring_data_max, current_value); | 140 | ring_data_max = std::max(ring_data_max, current_value); |
| @@ -143,42 +147,72 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio | |||
| 143 | return DriverResult::Success; | 147 | return DriverResult::Success; |
| 144 | } | 148 | } |
| 145 | 149 | ||
| 150 | DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, | ||
| 151 | bool& has_user_calibration) { | ||
| 152 | MagicSpiCalibration spi_magic{}; | ||
| 153 | const DriverResult result{ReadSPI(address, spi_magic)}; | ||
| 154 | has_user_calibration = false; | ||
| 155 | if (result == DriverResult::Success) { | ||
| 156 | has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 && | ||
| 157 | spi_magic.second == CalibrationMagic::USR_MAGIC_1; | ||
| 158 | } | ||
| 159 | return result; | ||
| 160 | } | ||
| 161 | |||
| 162 | u16 CalibrationProtocol::GetXAxisCalibrationValue(std::span<u8> block) const { | ||
| 163 | return static_cast<u16>(((block[1] & 0x0F) << 8) | block[0]); | ||
| 164 | } | ||
| 165 | |||
| 166 | u16 CalibrationProtocol::GetYAxisCalibrationValue(std::span<u8> block) const { | ||
| 167 | return static_cast<u16>((block[2] << 4) | (block[1] >> 4)); | ||
| 168 | } | ||
| 169 | |||
| 146 | void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) { | 170 | void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) { |
| 147 | constexpr u16 DefaultStickCenter{2048}; | 171 | constexpr u16 DefaultStickCenter{0x800}; |
| 148 | constexpr u16 DefaultStickRange{1740}; | 172 | constexpr u16 DefaultStickRange{0x6cc}; |
| 149 | 173 | ||
| 150 | if (calibration.x.center == 0xFFF || calibration.x.center == 0) { | 174 | calibration.x.center = ValidateValue(calibration.x.center, DefaultStickCenter); |
| 151 | calibration.x.center = DefaultStickCenter; | 175 | calibration.x.max = ValidateValue(calibration.x.max, DefaultStickRange); |
| 152 | } | 176 | calibration.x.min = ValidateValue(calibration.x.min, DefaultStickRange); |
| 153 | if (calibration.x.max == 0xFFF || calibration.x.max == 0) { | 177 | |
| 154 | calibration.x.max = DefaultStickRange; | 178 | calibration.y.center = ValidateValue(calibration.y.center, DefaultStickCenter); |
| 179 | calibration.y.max = ValidateValue(calibration.y.max, DefaultStickRange); | ||
| 180 | calibration.y.min = ValidateValue(calibration.y.min, DefaultStickRange); | ||
| 181 | } | ||
| 182 | |||
| 183 | void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) { | ||
| 184 | constexpr s16 DefaultAccelerometerScale{0x4000}; | ||
| 185 | constexpr s16 DefaultGyroScale{0x3be7}; | ||
| 186 | constexpr s16 DefaultOffset{0}; | ||
| 187 | |||
| 188 | for (auto& sensor : calibration.accelerometer) { | ||
| 189 | sensor.scale = ValidateValue(sensor.scale, DefaultAccelerometerScale); | ||
| 190 | sensor.offset = ValidateValue(sensor.offset, DefaultOffset); | ||
| 155 | } | 191 | } |
| 156 | if (calibration.x.min == 0xFFF || calibration.x.min == 0) { | 192 | for (auto& sensor : calibration.gyro) { |
| 157 | calibration.x.min = DefaultStickRange; | 193 | sensor.scale = ValidateValue(sensor.scale, DefaultGyroScale); |
| 194 | sensor.offset = ValidateValue(sensor.offset, DefaultOffset); | ||
| 158 | } | 195 | } |
| 196 | } | ||
| 159 | 197 | ||
| 160 | if (calibration.y.center == 0xFFF || calibration.y.center == 0) { | 198 | u16 CalibrationProtocol::ValidateValue(u16 value, u16 default_value) const { |
| 161 | calibration.y.center = DefaultStickCenter; | 199 | if (value == 0) { |
| 162 | } | 200 | return default_value; |
| 163 | if (calibration.y.max == 0xFFF || calibration.y.max == 0) { | ||
| 164 | calibration.y.max = DefaultStickRange; | ||
| 165 | } | 201 | } |
| 166 | if (calibration.y.min == 0xFFF || calibration.y.min == 0) { | 202 | if (value == 0xFFF) { |
| 167 | calibration.y.min = DefaultStickRange; | 203 | return default_value; |
| 168 | } | 204 | } |
| 205 | return value; | ||
| 169 | } | 206 | } |
| 170 | 207 | ||
| 171 | void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) { | 208 | s16 CalibrationProtocol::ValidateValue(s16 value, s16 default_value) const { |
| 172 | for (auto& sensor : calibration.accelerometer) { | 209 | if (value == 0) { |
| 173 | if (sensor.scale == 0) { | 210 | return default_value; |
| 174 | sensor.scale = 0x4000; | ||
| 175 | } | ||
| 176 | } | 211 | } |
| 177 | for (auto& sensor : calibration.gyro) { | 212 | if (value == 0xFFF) { |
| 178 | if (sensor.scale == 0) { | 213 | return default_value; |
| 179 | sensor.scale = 0x3be7; | ||
| 180 | } | ||
| 181 | } | 214 | } |
| 215 | return value; | ||
| 182 | } | 216 | } |
| 183 | 217 | ||
| 184 | } // namespace InputCommon::Joycon | 218 | } // namespace InputCommon::Joycon |
diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h index afb52a36a..c6fd0f729 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.h +++ b/src/input_common/helpers/joycon_protocol/calibration.h | |||
| @@ -53,9 +53,27 @@ public: | |||
| 53 | DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); | 53 | DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); |
| 54 | 54 | ||
| 55 | private: | 55 | private: |
| 56 | /// Returns true if the specified address corresponds to the magic value of user calibration | ||
| 57 | DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); | ||
| 58 | |||
| 59 | /// Converts a raw calibration block to an u16 value containing the x axis value | ||
| 60 | u16 GetXAxisCalibrationValue(std::span<u8> block) const; | ||
| 61 | |||
| 62 | /// Converts a raw calibration block to an u16 value containing the y axis value | ||
| 63 | u16 GetYAxisCalibrationValue(std::span<u8> block) const; | ||
| 64 | |||
| 65 | /// Ensures that all joystick calibration values are set | ||
| 56 | void ValidateCalibration(JoyStickCalibration& calibration); | 66 | void ValidateCalibration(JoyStickCalibration& calibration); |
| 67 | |||
| 68 | /// Ensures that all motion calibration values are set | ||
| 57 | void ValidateCalibration(MotionCalibration& calibration); | 69 | void ValidateCalibration(MotionCalibration& calibration); |
| 58 | 70 | ||
| 71 | /// Returns the default value if the value is either zero or 0xFFF | ||
| 72 | u16 ValidateValue(u16 value, u16 default_value) const; | ||
| 73 | |||
| 74 | /// Returns the default value if the value is either zero or 0xFFF | ||
| 75 | s16 ValidateValue(s16 value, s16 default_value) const; | ||
| 76 | |||
| 59 | s16 ring_data_max = 0; | 77 | s16 ring_data_max = 0; |
| 60 | s16 ring_data_default = 0; | 78 | s16 ring_data_default = 0; |
| 61 | s16 ring_data_min = 0; | 79 | s16 ring_data_min = 0; |
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 417d0dcc5..2b42a4555 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp | |||
| @@ -22,12 +22,9 @@ void JoyconCommonProtocol::SetNonBlocking() { | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { | 24 | DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { |
| 25 | std::vector<u8> buffer; | 25 | const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); |
| 26 | const auto result = ReadSPI(CalAddr::DEVICE_TYPE, 1, buffer); | ||
| 27 | controller_type = ControllerType::None; | ||
| 28 | 26 | ||
| 29 | if (result == DriverResult::Success) { | 27 | if (result == DriverResult::Success) { |
| 30 | controller_type = static_cast<ControllerType>(buffer[0]); | ||
| 31 | // Fallback to 3rd party pro controllers | 28 | // Fallback to 3rd party pro controllers |
| 32 | if (controller_type == ControllerType::None) { | 29 | if (controller_type == ControllerType::None) { |
| 33 | controller_type = ControllerType::Pro; | 30 | controller_type = ControllerType::Pro; |
| @@ -40,6 +37,7 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type | |||
| 40 | DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { | 37 | DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { |
| 41 | ControllerType controller_type{ControllerType::None}; | 38 | ControllerType controller_type{ControllerType::None}; |
| 42 | const auto result = GetDeviceType(controller_type); | 39 | const auto result = GetDeviceType(controller_type); |
| 40 | |||
| 43 | if (result != DriverResult::Success || controller_type == ControllerType::None) { | 41 | if (result != DriverResult::Success || controller_type == ControllerType::None) { |
| 44 | return DriverResult::UnsupportedControllerType; | 42 | return DriverResult::UnsupportedControllerType; |
| 45 | } | 43 | } |
| @@ -62,7 +60,7 @@ DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { | |||
| 62 | return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); | 60 | return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); |
| 63 | } | 61 | } |
| 64 | 62 | ||
| 65 | DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { | 63 | DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { |
| 66 | const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); | 64 | const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); |
| 67 | 65 | ||
| 68 | if (result == -1) { | 66 | if (result == -1) { |
| @@ -72,15 +70,15 @@ DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { | |||
| 72 | return DriverResult::Success; | 70 | return DriverResult::Success; |
| 73 | } | 71 | } |
| 74 | 72 | ||
| 75 | DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vector<u8>& output) { | 73 | DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, |
| 74 | SubCommandResponse& output) { | ||
| 76 | constexpr int timeout_mili = 66; | 75 | constexpr int timeout_mili = 66; |
| 77 | constexpr int MaxTries = 15; | 76 | constexpr int MaxTries = 15; |
| 78 | int tries = 0; | 77 | int tries = 0; |
| 79 | output.resize(MaxSubCommandResponseSize); | ||
| 80 | 78 | ||
| 81 | do { | 79 | do { |
| 82 | int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), | 80 | int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output), |
| 83 | MaxSubCommandResponseSize, timeout_mili); | 81 | sizeof(SubCommandResponse), timeout_mili); |
| 84 | 82 | ||
| 85 | if (result < 1) { | 83 | if (result < 1) { |
| 86 | LOG_ERROR(Input, "No response from joycon"); | 84 | LOG_ERROR(Input, "No response from joycon"); |
| @@ -88,27 +86,28 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vec | |||
| 88 | if (tries++ > MaxTries) { | 86 | if (tries++ > MaxTries) { |
| 89 | return DriverResult::Timeout; | 87 | return DriverResult::Timeout; |
| 90 | } | 88 | } |
| 91 | } while (output[0] != 0x21 && output[14] != static_cast<u8>(sc)); | 89 | } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && |
| 92 | 90 | output.sub_command != sc); | |
| 93 | if (output[0] != 0x21 && output[14] != static_cast<u8>(sc)) { | ||
| 94 | return DriverResult::WrongReply; | ||
| 95 | } | ||
| 96 | 91 | ||
| 97 | return DriverResult::Success; | 92 | return DriverResult::Success; |
| 98 | } | 93 | } |
| 99 | 94 | ||
| 100 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, | 95 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, |
| 101 | std::vector<u8>& output) { | 96 | SubCommandResponse& output) { |
| 102 | std::vector<u8> local_buffer(MaxResponseSize); | 97 | SubCommandPacket packet{ |
| 103 | 98 | .output_report = OutputReport::RUMBLE_AND_SUBCMD, | |
| 104 | local_buffer[0] = static_cast<u8>(OutputReport::RUMBLE_AND_SUBCMD); | 99 | .packet_counter = GetCounter(), |
| 105 | local_buffer[1] = GetCounter(); | 100 | .sub_command = sc, |
| 106 | local_buffer[10] = static_cast<u8>(sc); | 101 | .command_data = {}, |
| 107 | for (std::size_t i = 0; i < buffer.size(); ++i) { | 102 | }; |
| 108 | local_buffer[11 + i] = buffer[i]; | 103 | |
| 104 | if (buffer.size() > packet.command_data.size()) { | ||
| 105 | return DriverResult::InvalidParameters; | ||
| 109 | } | 106 | } |
| 110 | 107 | ||
| 111 | auto result = SendData(local_buffer); | 108 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); |
| 109 | |||
| 110 | auto result = SendData(packet); | ||
| 112 | 111 | ||
| 113 | if (result != DriverResult::Success) { | 112 | if (result != DriverResult::Success) { |
| 114 | return result; | 113 | return result; |
| @@ -120,44 +119,57 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const | |||
| 120 | } | 119 | } |
| 121 | 120 | ||
| 122 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { | 121 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { |
| 123 | std::vector<u8> output; | 122 | SubCommandResponse output{}; |
| 124 | return SendSubCommand(sc, buffer, output); | 123 | return SendSubCommand(sc, buffer, output); |
| 125 | } | 124 | } |
| 126 | 125 | ||
| 127 | DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { | 126 | DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { |
| 128 | std::vector<u8> local_buffer(MaxResponseSize); | 127 | SubCommandPacket packet{ |
| 129 | 128 | .output_report = OutputReport::MCU_DATA, | |
| 130 | local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); | 129 | .packet_counter = GetCounter(), |
| 131 | local_buffer[1] = GetCounter(); | 130 | .sub_command = sc, |
| 132 | local_buffer[10] = static_cast<u8>(sc); | 131 | .command_data = {}, |
| 133 | for (std::size_t i = 0; i < buffer.size(); ++i) { | 132 | }; |
| 134 | local_buffer[11 + i] = buffer[i]; | 133 | |
| 134 | if (buffer.size() > packet.command_data.size()) { | ||
| 135 | return DriverResult::InvalidParameters; | ||
| 135 | } | 136 | } |
| 136 | 137 | ||
| 137 | return SendData(local_buffer); | 138 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); |
| 139 | |||
| 140 | return SendData(packet); | ||
| 138 | } | 141 | } |
| 139 | 142 | ||
| 140 | DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { | 143 | DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { |
| 141 | std::vector<u8> local_buffer(MaxResponseSize); | 144 | VibrationPacket packet{ |
| 142 | 145 | .output_report = OutputReport::RUMBLE_ONLY, | |
| 143 | local_buffer[0] = static_cast<u8>(Joycon::OutputReport::RUMBLE_ONLY); | 146 | .packet_counter = GetCounter(), |
| 144 | local_buffer[1] = GetCounter(); | 147 | .vibration_data = {}, |
| 148 | }; | ||
| 149 | |||
| 150 | if (buffer.size() > packet.vibration_data.size()) { | ||
| 151 | return DriverResult::InvalidParameters; | ||
| 152 | } | ||
| 145 | 153 | ||
| 146 | memcpy(local_buffer.data() + 2, buffer.data(), buffer.size()); | 154 | memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); |
| 147 | 155 | ||
| 148 | return SendData(local_buffer); | 156 | return SendData(packet); |
| 149 | } | 157 | } |
| 150 | 158 | ||
| 151 | DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) { | 159 | DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { |
| 160 | constexpr std::size_t HeaderSize = 5; | ||
| 152 | constexpr std::size_t MaxTries = 10; | 161 | constexpr std::size_t MaxTries = 10; |
| 153 | std::size_t tries = 0; | 162 | std::size_t tries = 0; |
| 154 | std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, size}; | 163 | SubCommandResponse response{}; |
| 155 | std::vector<u8> local_buffer(size + 20); | 164 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; |
| 156 | 165 | const ReadSpiPacket packet_data{ | |
| 157 | buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); | 166 | .spi_address = addr, |
| 158 | buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8); | 167 | .size = static_cast<u8>(output.size()), |
| 168 | }; | ||
| 169 | |||
| 170 | memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); | ||
| 159 | do { | 171 | do { |
| 160 | const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, local_buffer); | 172 | const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); |
| 161 | if (result != DriverResult::Success) { | 173 | if (result != DriverResult::Success) { |
| 162 | return result; | 174 | return result; |
| 163 | } | 175 | } |
| @@ -165,10 +177,14 @@ DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8 | |||
| 165 | if (tries++ > MaxTries) { | 177 | if (tries++ > MaxTries) { |
| 166 | return DriverResult::Timeout; | 178 | return DriverResult::Timeout; |
| 167 | } | 179 | } |
| 168 | } while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]); | 180 | } while (response.spi_address != addr); |
| 181 | |||
| 182 | if (response.command_data.size() < packet_data.size + HeaderSize) { | ||
| 183 | return DriverResult::WrongReply; | ||
| 184 | } | ||
| 169 | 185 | ||
| 170 | // Remove header from output | 186 | // Remove header from output |
| 171 | output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.begin() + 20 + size); | 187 | memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); |
| 172 | return DriverResult::Success; | 188 | return DriverResult::Success; |
| 173 | } | 189 | } |
| 174 | 190 | ||
| @@ -177,7 +193,7 @@ DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { | |||
| 177 | const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); | 193 | const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); |
| 178 | 194 | ||
| 179 | if (result != DriverResult::Success) { | 195 | if (result != DriverResult::Success) { |
| 180 | LOG_ERROR(Input, "SendMCUData failed with error {}", result); | 196 | LOG_ERROR(Input, "Failed with error {}", result); |
| 181 | } | 197 | } |
| 182 | 198 | ||
| 183 | return result; | 199 | return result; |
| @@ -192,22 +208,21 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { | |||
| 192 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); | 208 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); |
| 193 | 209 | ||
| 194 | if (result != DriverResult::Success) { | 210 | if (result != DriverResult::Success) { |
| 195 | LOG_ERROR(Input, "Set MCU config failed with error {}", result); | 211 | LOG_ERROR(Input, "Failed with error {}", result); |
| 196 | } | 212 | } |
| 197 | 213 | ||
| 198 | return result; | 214 | return result; |
| 199 | } | 215 | } |
| 200 | 216 | ||
| 201 | DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, | 217 | DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, |
| 202 | std::vector<u8>& output) { | 218 | MCUCommandResponse& output) { |
| 203 | const int report_mode = static_cast<u8>(report_mode_); | ||
| 204 | constexpr int TimeoutMili = 200; | 219 | constexpr int TimeoutMili = 200; |
| 205 | constexpr int MaxTries = 9; | 220 | constexpr int MaxTries = 9; |
| 206 | int tries = 0; | 221 | int tries = 0; |
| 207 | output.resize(0x170); | ||
| 208 | 222 | ||
| 209 | do { | 223 | do { |
| 210 | int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), 0x170, TimeoutMili); | 224 | int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output), |
| 225 | sizeof(MCUCommandResponse), TimeoutMili); | ||
| 211 | 226 | ||
| 212 | if (result < 1) { | 227 | if (result < 1) { |
| 213 | LOG_ERROR(Input, "No response from joycon attempt {}", tries); | 228 | LOG_ERROR(Input, "No response from joycon attempt {}", tries); |
| @@ -215,28 +230,29 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, | |||
| 215 | if (tries++ > MaxTries) { | 230 | if (tries++ > MaxTries) { |
| 216 | return DriverResult::Timeout; | 231 | return DriverResult::Timeout; |
| 217 | } | 232 | } |
| 218 | } while (output[0] != report_mode || output[49] == 0xFF); | 233 | } while (output.input_report.report_mode != report_mode || |
| 219 | 234 | output.mcu_report == MCUReport::EmptyAwaitingCmd); | |
| 220 | if (output[0] != report_mode || output[49] == 0xFF) { | ||
| 221 | return DriverResult::WrongReply; | ||
| 222 | } | ||
| 223 | 235 | ||
| 224 | return DriverResult::Success; | 236 | return DriverResult::Success; |
| 225 | } | 237 | } |
| 226 | 238 | ||
| 227 | DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, | 239 | DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, |
| 228 | std::span<const u8> buffer, | 240 | std::span<const u8> buffer, |
| 229 | std::vector<u8>& output) { | 241 | MCUCommandResponse& output) { |
| 230 | std::vector<u8> local_buffer(MaxResponseSize); | 242 | SubCommandPacket packet{ |
| 231 | 243 | .output_report = OutputReport::MCU_DATA, | |
| 232 | local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); | 244 | .packet_counter = GetCounter(), |
| 233 | local_buffer[1] = GetCounter(); | 245 | .sub_command = sc, |
| 234 | local_buffer[9] = static_cast<u8>(sc); | 246 | .command_data = {}, |
| 235 | for (std::size_t i = 0; i < buffer.size(); ++i) { | 247 | }; |
| 236 | local_buffer[10 + i] = buffer[i]; | 248 | |
| 249 | if (buffer.size() > packet.command_data.size()) { | ||
| 250 | return DriverResult::InvalidParameters; | ||
| 237 | } | 251 | } |
| 238 | 252 | ||
| 239 | auto result = SendData(local_buffer); | 253 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); |
| 254 | |||
| 255 | auto result = SendData(packet); | ||
| 240 | 256 | ||
| 241 | if (result != DriverResult::Success) { | 257 | if (result != DriverResult::Success) { |
| 242 | return result; | 258 | return result; |
| @@ -248,7 +264,7 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubComman | |||
| 248 | } | 264 | } |
| 249 | 265 | ||
| 250 | DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { | 266 | DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { |
| 251 | std::vector<u8> output; | 267 | MCUCommandResponse output{}; |
| 252 | constexpr std::size_t MaxTries{8}; | 268 | constexpr std::size_t MaxTries{8}; |
| 253 | std::size_t tries{}; | 269 | std::size_t tries{}; |
| 254 | 270 | ||
| @@ -263,7 +279,8 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod | |||
| 263 | if (tries++ > MaxTries) { | 279 | if (tries++ > MaxTries) { |
| 264 | return DriverResult::WrongReply; | 280 | return DriverResult::WrongReply; |
| 265 | } | 281 | } |
| 266 | } while (output[49] != 1 || output[56] != static_cast<u8>(mode)); | 282 | } while (output.mcu_report != MCUReport::StateReport || |
| 283 | output.mcu_data[6] != static_cast<u8>(mode)); | ||
| 267 | 284 | ||
| 268 | return DriverResult::Success; | 285 | return DriverResult::Success; |
| 269 | } | 286 | } |
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h index 903bcf402..f44f73ba4 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.h +++ b/src/input_common/helpers/joycon_protocol/common_protocol.h | |||
| @@ -57,22 +57,31 @@ public: | |||
| 57 | * Sends data to the joycon device | 57 | * Sends data to the joycon device |
| 58 | * @param buffer data to be send | 58 | * @param buffer data to be send |
| 59 | */ | 59 | */ |
| 60 | DriverResult SendData(std::span<const u8> buffer); | 60 | DriverResult SendRawData(std::span<const u8> buffer); |
| 61 | |||
| 62 | template <typename Output> | ||
| 63 | requires std::is_trivially_copyable_v<Output> | ||
| 64 | DriverResult SendData(const Output& output) { | ||
| 65 | std::array<u8, sizeof(Output)> buffer; | ||
| 66 | std::memcpy(buffer.data(), &output, sizeof(Output)); | ||
| 67 | return SendRawData(buffer); | ||
| 68 | } | ||
| 61 | 69 | ||
| 62 | /** | 70 | /** |
| 63 | * Waits for incoming data of the joycon device that matchs the subcommand | 71 | * Waits for incoming data of the joycon device that matchs the subcommand |
| 64 | * @param sub_command type of data to be returned | 72 | * @param sub_command type of data to be returned |
| 65 | * @returns a buffer containing the responce | 73 | * @returns a buffer containing the response |
| 66 | */ | 74 | */ |
| 67 | DriverResult GetSubCommandResponse(SubCommand sub_command, std::vector<u8>& output); | 75 | DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output); |
| 68 | 76 | ||
| 69 | /** | 77 | /** |
| 70 | * Sends a sub command to the device and waits for it's reply | 78 | * Sends a sub command to the device and waits for it's reply |
| 71 | * @param sc sub command to be send | 79 | * @param sc sub command to be send |
| 72 | * @param buffer data to be send | 80 | * @param buffer data to be send |
| 73 | * @returns output buffer containing the responce | 81 | * @returns output buffer containing the response |
| 74 | */ | 82 | */ |
| 75 | DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output); | 83 | DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, |
| 84 | SubCommandResponse& output); | ||
| 76 | 85 | ||
| 77 | /** | 86 | /** |
| 78 | * Sends a sub command to the device and waits for it's reply and ignores the output | 87 | * Sends a sub command to the device and waits for it's reply and ignores the output |
| @@ -97,10 +106,29 @@ public: | |||
| 97 | /** | 106 | /** |
| 98 | * Reads the SPI memory stored on the joycon | 107 | * Reads the SPI memory stored on the joycon |
| 99 | * @param Initial address location | 108 | * @param Initial address location |
| 100 | * @param size in bytes to be read | 109 | * @returns output buffer containing the response |
| 101 | * @returns output buffer containing the responce | ||
| 102 | */ | 110 | */ |
| 103 | DriverResult ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output); | 111 | DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); |
| 112 | |||
| 113 | /** | ||
| 114 | * Reads the SPI memory stored on the joycon | ||
| 115 | * @param Initial address location | ||
| 116 | * @returns output object containing the response | ||
| 117 | */ | ||
| 118 | template <typename Output> | ||
| 119 | requires std::is_trivially_copyable_v<Output> | ||
| 120 | DriverResult ReadSPI(SpiAddress addr, Output& output) { | ||
| 121 | std::array<u8, sizeof(Output)> buffer; | ||
| 122 | output = {}; | ||
| 123 | |||
| 124 | const auto result = ReadRawSPI(addr, buffer); | ||
| 125 | if (result != DriverResult::Success) { | ||
| 126 | return result; | ||
| 127 | } | ||
| 128 | |||
| 129 | std::memcpy(&output, buffer.data(), sizeof(Output)); | ||
| 130 | return DriverResult::Success; | ||
| 131 | } | ||
| 104 | 132 | ||
| 105 | /** | 133 | /** |
| 106 | * Enables MCU chip on the joycon | 134 | * Enables MCU chip on the joycon |
| @@ -117,19 +145,19 @@ public: | |||
| 117 | /** | 145 | /** |
| 118 | * Waits until there's MCU data available. On timeout returns error | 146 | * Waits until there's MCU data available. On timeout returns error |
| 119 | * @param report mode of the expected reply | 147 | * @param report mode of the expected reply |
| 120 | * @returns a buffer containing the responce | 148 | * @returns a buffer containing the response |
| 121 | */ | 149 | */ |
| 122 | DriverResult GetMCUDataResponse(ReportMode report_mode_, std::vector<u8>& output); | 150 | DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output); |
| 123 | 151 | ||
| 124 | /** | 152 | /** |
| 125 | * Sends data to the MCU chip and waits for it's reply | 153 | * Sends data to the MCU chip and waits for it's reply |
| 126 | * @param report mode of the expected reply | 154 | * @param report mode of the expected reply |
| 127 | * @param sub command to be send | 155 | * @param sub command to be send |
| 128 | * @param buffer data to be send | 156 | * @param buffer data to be send |
| 129 | * @returns output buffer containing the responce | 157 | * @returns output buffer containing the response |
| 130 | */ | 158 | */ |
| 131 | DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer, | 159 | DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer, |
| 132 | std::vector<u8>& output); | 160 | MCUCommandResponse& output); |
| 133 | 161 | ||
| 134 | /** | 162 | /** |
| 135 | * Wait's until the MCU chip is on the specified mode | 163 | * Wait's until the MCU chip is on the specified mode |
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp index 52bb8b61a..548a4b9e3 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp +++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp | |||
| @@ -19,15 +19,26 @@ DriverResult GenericProtocol::EnableActiveMode() { | |||
| 19 | return SetReportMode(ReportMode::STANDARD_FULL_60HZ); | 19 | return SetReportMode(ReportMode::STANDARD_FULL_60HZ); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | DriverResult GenericProtocol::SetLowPowerMode(bool enable) { | ||
| 23 | ScopedSetBlocking sb(this); | ||
| 24 | const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; | ||
| 25 | return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer); | ||
| 26 | } | ||
| 27 | |||
| 28 | DriverResult GenericProtocol::TriggersElapsed() { | ||
| 29 | ScopedSetBlocking sb(this); | ||
| 30 | return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {}); | ||
| 31 | } | ||
| 32 | |||
| 22 | DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { | 33 | DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { |
| 23 | ScopedSetBlocking sb(this); | 34 | ScopedSetBlocking sb(this); |
| 24 | std::vector<u8> output; | 35 | SubCommandResponse output{}; |
| 25 | 36 | ||
| 26 | const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); | 37 | const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); |
| 27 | 38 | ||
| 28 | device_info = {}; | 39 | device_info = {}; |
| 29 | if (result == DriverResult::Success) { | 40 | if (result == DriverResult::Success) { |
| 30 | memcpy(&device_info, output.data(), sizeof(DeviceInfo)); | 41 | device_info = output.device_info; |
| 31 | } | 42 | } |
| 32 | 43 | ||
| 33 | return result; | 44 | return result; |
| @@ -60,8 +71,8 @@ DriverResult GenericProtocol::GetBattery(u32& battery_level) { | |||
| 60 | 71 | ||
| 61 | DriverResult GenericProtocol::GetColor(Color& color) { | 72 | DriverResult GenericProtocol::GetColor(Color& color) { |
| 62 | ScopedSetBlocking sb(this); | 73 | ScopedSetBlocking sb(this); |
| 63 | std::vector<u8> buffer; | 74 | std::array<u8, 12> buffer{}; |
| 64 | const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer); | 75 | const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer); |
| 65 | 76 | ||
| 66 | color = {}; | 77 | color = {}; |
| 67 | if (result == DriverResult::Success) { | 78 | if (result == DriverResult::Success) { |
| @@ -76,8 +87,8 @@ DriverResult GenericProtocol::GetColor(Color& color) { | |||
| 76 | 87 | ||
| 77 | DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { | 88 | DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { |
| 78 | ScopedSetBlocking sb(this); | 89 | ScopedSetBlocking sb(this); |
| 79 | std::vector<u8> buffer; | 90 | std::array<u8, 16> buffer{}; |
| 80 | const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer); | 91 | const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer); |
| 81 | 92 | ||
| 82 | serial_number = {}; | 93 | serial_number = {}; |
| 83 | if (result == DriverResult::Success) { | 94 | if (result == DriverResult::Success) { |
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.h b/src/input_common/helpers/joycon_protocol/generic_functions.h index 239bb7dbf..424831e81 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.h +++ b/src/input_common/helpers/joycon_protocol/generic_functions.h | |||
| @@ -25,6 +25,12 @@ public: | |||
| 25 | /// Enables active mode. This mode will return the current status every 5-15ms | 25 | /// Enables active mode. This mode will return the current status every 5-15ms |
| 26 | DriverResult EnableActiveMode(); | 26 | DriverResult EnableActiveMode(); |
| 27 | 27 | ||
| 28 | /// Enables or disables the low power mode | ||
| 29 | DriverResult SetLowPowerMode(bool enable); | ||
| 30 | |||
| 31 | /// Unknown function used by the switch | ||
| 32 | DriverResult TriggersElapsed(); | ||
| 33 | |||
| 28 | /** | 34 | /** |
| 29 | * Sends a request to obtain the joycon firmware and mac from handle | 35 | * Sends a request to obtain the joycon firmware and mac from handle |
| 30 | * @returns controller device info | 36 | * @returns controller device info |
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp index 09e17bc5b..731fd5981 100644 --- a/src/input_common/helpers/joycon_protocol/irs.cpp +++ b/src/input_common/helpers/joycon_protocol/irs.cpp | |||
| @@ -132,7 +132,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { | |||
| 132 | DriverResult IrsProtocol::ConfigureIrs() { | 132 | DriverResult IrsProtocol::ConfigureIrs() { |
| 133 | LOG_DEBUG(Input, "Configure IRS"); | 133 | LOG_DEBUG(Input, "Configure IRS"); |
| 134 | constexpr std::size_t max_tries = 28; | 134 | constexpr std::size_t max_tries = 28; |
| 135 | std::vector<u8> output; | 135 | SubCommandResponse output{}; |
| 136 | std::size_t tries = 0; | 136 | std::size_t tries = 0; |
| 137 | 137 | ||
| 138 | const IrsConfigure irs_configuration{ | 138 | const IrsConfigure irs_configuration{ |
| @@ -158,7 +158,7 @@ DriverResult IrsProtocol::ConfigureIrs() { | |||
| 158 | if (tries++ >= max_tries) { | 158 | if (tries++ >= max_tries) { |
| 159 | return DriverResult::WrongReply; | 159 | return DriverResult::WrongReply; |
| 160 | } | 160 | } |
| 161 | } while (output[15] != 0x0b); | 161 | } while (output.command_data[0] != 0x0b); |
| 162 | 162 | ||
| 163 | return DriverResult::Success; | 163 | return DriverResult::Success; |
| 164 | } | 164 | } |
| @@ -167,7 +167,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() { | |||
| 167 | LOG_DEBUG(Input, "WriteRegistersStep1"); | 167 | LOG_DEBUG(Input, "WriteRegistersStep1"); |
| 168 | DriverResult result{DriverResult::Success}; | 168 | DriverResult result{DriverResult::Success}; |
| 169 | constexpr std::size_t max_tries = 28; | 169 | constexpr std::size_t max_tries = 28; |
| 170 | std::vector<u8> output; | 170 | SubCommandResponse output{}; |
| 171 | std::size_t tries = 0; | 171 | std::size_t tries = 0; |
| 172 | 172 | ||
| 173 | const IrsWriteRegisters irs_registers{ | 173 | const IrsWriteRegisters irs_registers{ |
| @@ -218,7 +218,8 @@ DriverResult IrsProtocol::WriteRegistersStep1() { | |||
| 218 | if (tries++ >= max_tries) { | 218 | if (tries++ >= max_tries) { |
| 219 | return DriverResult::WrongReply; | 219 | return DriverResult::WrongReply; |
| 220 | } | 220 | } |
| 221 | } while (!(output[15] == 0x13 && output[17] == 0x07) && output[15] != 0x23); | 221 | } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && |
| 222 | output.command_data[0] != 0x23); | ||
| 222 | 223 | ||
| 223 | return DriverResult::Success; | 224 | return DriverResult::Success; |
| 224 | } | 225 | } |
| @@ -226,7 +227,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() { | |||
| 226 | DriverResult IrsProtocol::WriteRegistersStep2() { | 227 | DriverResult IrsProtocol::WriteRegistersStep2() { |
| 227 | LOG_DEBUG(Input, "WriteRegistersStep2"); | 228 | LOG_DEBUG(Input, "WriteRegistersStep2"); |
| 228 | constexpr std::size_t max_tries = 28; | 229 | constexpr std::size_t max_tries = 28; |
| 229 | std::vector<u8> output; | 230 | SubCommandResponse output{}; |
| 230 | std::size_t tries = 0; | 231 | std::size_t tries = 0; |
| 231 | 232 | ||
| 232 | const IrsWriteRegisters irs_registers{ | 233 | const IrsWriteRegisters irs_registers{ |
| @@ -260,7 +261,7 @@ DriverResult IrsProtocol::WriteRegistersStep2() { | |||
| 260 | if (tries++ >= max_tries) { | 261 | if (tries++ >= max_tries) { |
| 261 | return DriverResult::WrongReply; | 262 | return DriverResult::WrongReply; |
| 262 | } | 263 | } |
| 263 | } while (output[15] != 0x13 && output[15] != 0x23); | 264 | } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23); |
| 264 | 265 | ||
| 265 | return DriverResult::Success; | 266 | return DriverResult::Success; |
| 266 | } | 267 | } |
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index e2d47349f..b91934990 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h | |||
| @@ -19,20 +19,24 @@ | |||
| 19 | namespace InputCommon::Joycon { | 19 | namespace InputCommon::Joycon { |
| 20 | constexpr u32 MaxErrorCount = 50; | 20 | constexpr u32 MaxErrorCount = 50; |
| 21 | constexpr u32 MaxBufferSize = 368; | 21 | constexpr u32 MaxBufferSize = 368; |
| 22 | constexpr u32 MaxResponseSize = 49; | ||
| 23 | constexpr u32 MaxSubCommandResponseSize = 64; | ||
| 24 | constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; | 22 | constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; |
| 25 | 23 | ||
| 26 | using MacAddress = std::array<u8, 6>; | 24 | using MacAddress = std::array<u8, 6>; |
| 27 | using SerialNumber = std::array<u8, 15>; | 25 | using SerialNumber = std::array<u8, 15>; |
| 28 | 26 | ||
| 29 | enum class ControllerType { | 27 | enum class ControllerType : u8 { |
| 30 | None, | 28 | None = 0x00, |
| 31 | Left, | 29 | Left = 0x01, |
| 32 | Right, | 30 | Right = 0x02, |
| 33 | Pro, | 31 | Pro = 0x03, |
| 34 | Grip, | 32 | Dual = 0x05, // TODO: Verify this id |
| 35 | Dual, | 33 | LarkHvc1 = 0x07, |
| 34 | LarkHvc2 = 0x08, | ||
| 35 | LarkNesLeft = 0x09, | ||
| 36 | LarkNesRight = 0x0A, | ||
| 37 | Lucia = 0x0B, | ||
| 38 | Lagon = 0x0C, | ||
| 39 | Lager = 0x0D, | ||
| 36 | }; | 40 | }; |
| 37 | 41 | ||
| 38 | enum class PadAxes { | 42 | enum class PadAxes { |
| @@ -99,14 +103,6 @@ enum class OutputReport : u8 { | |||
| 99 | USB_CMD = 0x80, | 103 | USB_CMD = 0x80, |
| 100 | }; | 104 | }; |
| 101 | 105 | ||
| 102 | enum class InputReport : u8 { | ||
| 103 | SUBCMD_REPLY = 0x21, | ||
| 104 | STANDARD_FULL_60HZ = 0x30, | ||
| 105 | NFC_IR_MODE_60HZ = 0x31, | ||
| 106 | SIMPLE_HID_MODE = 0x3F, | ||
| 107 | INPUT_USB_RESPONSE = 0x81, | ||
| 108 | }; | ||
| 109 | |||
| 110 | enum class FeatureReport : u8 { | 106 | enum class FeatureReport : u8 { |
| 111 | Last_SUBCMD = 0x02, | 107 | Last_SUBCMD = 0x02, |
| 112 | OTA_GW_UPGRADE = 0x70, | 108 | OTA_GW_UPGRADE = 0x70, |
| @@ -129,6 +125,7 @@ enum class SubCommand : u8 { | |||
| 129 | LOW_POWER_MODE = 0x08, | 125 | LOW_POWER_MODE = 0x08, |
| 130 | SPI_FLASH_READ = 0x10, | 126 | SPI_FLASH_READ = 0x10, |
| 131 | SPI_FLASH_WRITE = 0x11, | 127 | SPI_FLASH_WRITE = 0x11, |
| 128 | SPI_SECTOR_ERASE = 0x12, | ||
| 132 | RESET_MCU = 0x20, | 129 | RESET_MCU = 0x20, |
| 133 | SET_MCU_CONFIG = 0x21, | 130 | SET_MCU_CONFIG = 0x21, |
| 134 | SET_MCU_STATE = 0x22, | 131 | SET_MCU_STATE = 0x22, |
| @@ -142,9 +139,10 @@ enum class SubCommand : u8 { | |||
| 142 | ENABLE_VIBRATION = 0x48, | 139 | ENABLE_VIBRATION = 0x48, |
| 143 | GET_REGULATED_VOLTAGE = 0x50, | 140 | GET_REGULATED_VOLTAGE = 0x50, |
| 144 | SET_EXTERNAL_CONFIG = 0x58, | 141 | SET_EXTERNAL_CONFIG = 0x58, |
| 145 | UNKNOWN_RINGCON = 0x59, | 142 | GET_EXTERNAL_DEVICE_INFO = 0x59, |
| 146 | UNKNOWN_RINGCON2 = 0x5A, | 143 | ENABLE_EXTERNAL_POLLING = 0x5A, |
| 147 | UNKNOWN_RINGCON3 = 0x5C, | 144 | DISABLE_EXTERNAL_POLLING = 0x5B, |
| 145 | SET_EXTERNAL_FORMAT_CONFIG = 0x5C, | ||
| 148 | }; | 146 | }; |
| 149 | 147 | ||
| 150 | enum class UsbSubCommand : u8 { | 148 | enum class UsbSubCommand : u8 { |
| @@ -158,26 +156,31 @@ enum class UsbSubCommand : u8 { | |||
| 158 | SEND_UART = 0x92, | 156 | SEND_UART = 0x92, |
| 159 | }; | 157 | }; |
| 160 | 158 | ||
| 161 | enum class CalMagic : u8 { | 159 | enum class CalibrationMagic : u8 { |
| 162 | USR_MAGIC_0 = 0xB2, | 160 | USR_MAGIC_0 = 0xB2, |
| 163 | USR_MAGIC_1 = 0xA1, | 161 | USR_MAGIC_1 = 0xA1, |
| 164 | USRR_MAGI_SIZE = 2, | ||
| 165 | }; | 162 | }; |
| 166 | 163 | ||
| 167 | enum class CalAddr { | 164 | enum class SpiAddress : u16 { |
| 168 | SERIAL_NUMBER = 0X6000, | 165 | MAGIC = 0x0000, |
| 169 | DEVICE_TYPE = 0X6012, | 166 | MAC_ADDRESS = 0x0015, |
| 170 | COLOR_EXIST = 0X601B, | 167 | PAIRING_INFO = 0x2000, |
| 171 | FACT_LEFT_DATA = 0X603d, | 168 | SHIPMENT = 0x5000, |
| 172 | FACT_RIGHT_DATA = 0X6046, | 169 | SERIAL_NUMBER = 0x6000, |
| 173 | COLOR_DATA = 0X6050, | 170 | DEVICE_TYPE = 0x6012, |
| 174 | FACT_IMU_DATA = 0X6020, | 171 | FORMAT_VERSION = 0x601B, |
| 175 | USER_LEFT_MAGIC = 0X8010, | 172 | FACT_IMU_DATA = 0x6020, |
| 176 | USER_LEFT_DATA = 0X8012, | 173 | FACT_LEFT_DATA = 0x603d, |
| 177 | USER_RIGHT_MAGIC = 0X801B, | 174 | FACT_RIGHT_DATA = 0x6046, |
| 178 | USER_RIGHT_DATA = 0X801D, | 175 | COLOR_DATA = 0x6050, |
| 179 | USER_IMU_MAGIC = 0X8026, | 176 | DESIGN_VARIATION = 0x605C, |
| 180 | USER_IMU_DATA = 0X8028, | 177 | SENSOR_DATA = 0x6080, |
| 178 | USER_LEFT_MAGIC = 0x8010, | ||
| 179 | USER_LEFT_DATA = 0x8012, | ||
| 180 | USER_RIGHT_MAGIC = 0x801B, | ||
| 181 | USER_RIGHT_DATA = 0x801D, | ||
| 182 | USER_IMU_MAGIC = 0x8026, | ||
| 183 | USER_IMU_DATA = 0x8028, | ||
| 181 | }; | 184 | }; |
| 182 | 185 | ||
| 183 | enum class ReportMode : u8 { | 186 | enum class ReportMode : u8 { |
| @@ -185,10 +188,12 @@ enum class ReportMode : u8 { | |||
| 185 | ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01, | 188 | ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01, |
| 186 | ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02, | 189 | ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02, |
| 187 | ACTIVE_POLLING_IR_CAMERA_DATA = 0x03, | 190 | ACTIVE_POLLING_IR_CAMERA_DATA = 0x03, |
| 191 | SUBCMD_REPLY = 0x21, | ||
| 188 | MCU_UPDATE_STATE = 0x23, | 192 | MCU_UPDATE_STATE = 0x23, |
| 189 | STANDARD_FULL_60HZ = 0x30, | 193 | STANDARD_FULL_60HZ = 0x30, |
| 190 | NFC_IR_MODE_60HZ = 0x31, | 194 | NFC_IR_MODE_60HZ = 0x31, |
| 191 | SIMPLE_HID_MODE = 0x3F, | 195 | SIMPLE_HID_MODE = 0x3F, |
| 196 | INPUT_USB_RESPONSE = 0x81, | ||
| 192 | }; | 197 | }; |
| 193 | 198 | ||
| 194 | enum class GyroSensitivity : u8 { | 199 | enum class GyroSensitivity : u8 { |
| @@ -359,10 +364,16 @@ enum class IrRegistersAddress : u16 { | |||
| 359 | DenoiseColor = 0x6901, | 364 | DenoiseColor = 0x6901, |
| 360 | }; | 365 | }; |
| 361 | 366 | ||
| 367 | enum class ExternalDeviceId : u16 { | ||
| 368 | RingController = 0x2000, | ||
| 369 | Starlink = 0x2800, | ||
| 370 | }; | ||
| 371 | |||
| 362 | enum class DriverResult { | 372 | enum class DriverResult { |
| 363 | Success, | 373 | Success, |
| 364 | WrongReply, | 374 | WrongReply, |
| 365 | Timeout, | 375 | Timeout, |
| 376 | InvalidParameters, | ||
| 366 | UnsupportedControllerType, | 377 | UnsupportedControllerType, |
| 367 | HandleInUse, | 378 | HandleInUse, |
| 368 | ErrorReadingData, | 379 | ErrorReadingData, |
| @@ -395,10 +406,35 @@ struct MotionData { | |||
| 395 | u64 delta_timestamp{}; | 406 | u64 delta_timestamp{}; |
| 396 | }; | 407 | }; |
| 397 | 408 | ||
| 409 | // Output from SPI read command containing user calibration magic | ||
| 410 | struct MagicSpiCalibration { | ||
| 411 | CalibrationMagic first; | ||
| 412 | CalibrationMagic second; | ||
| 413 | }; | ||
| 414 | static_assert(sizeof(MagicSpiCalibration) == 0x2, "MagicSpiCalibration is an invalid size"); | ||
| 415 | |||
| 416 | // Output from SPI read command containing left joystick calibration | ||
| 417 | struct JoystickLeftSpiCalibration { | ||
| 418 | std::array<u8, 3> max; | ||
| 419 | std::array<u8, 3> center; | ||
| 420 | std::array<u8, 3> min; | ||
| 421 | }; | ||
| 422 | static_assert(sizeof(JoystickLeftSpiCalibration) == 0x9, | ||
| 423 | "JoystickLeftSpiCalibration is an invalid size"); | ||
| 424 | |||
| 425 | // Output from SPI read command containing right joystick calibration | ||
| 426 | struct JoystickRightSpiCalibration { | ||
| 427 | std::array<u8, 3> center; | ||
| 428 | std::array<u8, 3> min; | ||
| 429 | std::array<u8, 3> max; | ||
| 430 | }; | ||
| 431 | static_assert(sizeof(JoystickRightSpiCalibration) == 0x9, | ||
| 432 | "JoystickRightSpiCalibration is an invalid size"); | ||
| 433 | |||
| 398 | struct JoyStickAxisCalibration { | 434 | struct JoyStickAxisCalibration { |
| 399 | u16 max{1}; | 435 | u16 max; |
| 400 | u16 min{1}; | 436 | u16 min; |
| 401 | u16 center{0}; | 437 | u16 center; |
| 402 | }; | 438 | }; |
| 403 | 439 | ||
| 404 | struct JoyStickCalibration { | 440 | struct JoyStickCalibration { |
| @@ -406,6 +442,14 @@ struct JoyStickCalibration { | |||
| 406 | JoyStickAxisCalibration y; | 442 | JoyStickAxisCalibration y; |
| 407 | }; | 443 | }; |
| 408 | 444 | ||
| 445 | struct ImuSpiCalibration { | ||
| 446 | std::array<s16, 3> accelerometer_offset; | ||
| 447 | std::array<s16, 3> accelerometer_scale; | ||
| 448 | std::array<s16, 3> gyroscope_offset; | ||
| 449 | std::array<s16, 3> gyroscope_scale; | ||
| 450 | }; | ||
| 451 | static_assert(sizeof(ImuSpiCalibration) == 0x18, "ImuSpiCalibration is an invalid size"); | ||
| 452 | |||
| 409 | struct RingCalibration { | 453 | struct RingCalibration { |
| 410 | s16 default_value; | 454 | s16 default_value; |
| 411 | s16 max_value; | 455 | s16 max_value; |
| @@ -452,7 +496,7 @@ static_assert(sizeof(MCUConfig) == 0x26, "MCUConfig is an invalid size"); | |||
| 452 | 496 | ||
| 453 | #pragma pack(push, 1) | 497 | #pragma pack(push, 1) |
| 454 | struct InputReportPassive { | 498 | struct InputReportPassive { |
| 455 | InputReport report_mode; | 499 | ReportMode report_mode; |
| 456 | u16 button_input; | 500 | u16 button_input; |
| 457 | u8 stick_state; | 501 | u8 stick_state; |
| 458 | std::array<u8, 10> unknown_data; | 502 | std::array<u8, 10> unknown_data; |
| @@ -460,7 +504,7 @@ struct InputReportPassive { | |||
| 460 | static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size"); | 504 | static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size"); |
| 461 | 505 | ||
| 462 | struct InputReportActive { | 506 | struct InputReportActive { |
| 463 | InputReport report_mode; | 507 | ReportMode report_mode; |
| 464 | u8 packet_id; | 508 | u8 packet_id; |
| 465 | Battery battery_status; | 509 | Battery battery_status; |
| 466 | std::array<u8, 3> button_input; | 510 | std::array<u8, 3> button_input; |
| @@ -474,7 +518,7 @@ struct InputReportActive { | |||
| 474 | static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size"); | 518 | static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size"); |
| 475 | 519 | ||
| 476 | struct InputReportNfcIr { | 520 | struct InputReportNfcIr { |
| 477 | InputReport report_mode; | 521 | ReportMode report_mode; |
| 478 | u8 packet_id; | 522 | u8 packet_id; |
| 479 | Battery battery_status; | 523 | Battery battery_status; |
| 480 | std::array<u8, 3> button_input; | 524 | std::array<u8, 3> button_input; |
| @@ -487,14 +531,6 @@ struct InputReportNfcIr { | |||
| 487 | static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size"); | 531 | static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size"); |
| 488 | #pragma pack(pop) | 532 | #pragma pack(pop) |
| 489 | 533 | ||
| 490 | struct IMUCalibration { | ||
| 491 | std::array<s16, 3> accelerometer_offset; | ||
| 492 | std::array<s16, 3> accelerometer_scale; | ||
| 493 | std::array<s16, 3> gyroscope_offset; | ||
| 494 | std::array<s16, 3> gyroscope_scale; | ||
| 495 | }; | ||
| 496 | static_assert(sizeof(IMUCalibration) == 0x18, "IMUCalibration is an invalid size"); | ||
| 497 | |||
| 498 | struct NFCReadBlock { | 534 | struct NFCReadBlock { |
| 499 | u8 start; | 535 | u8 start; |
| 500 | u8 end; | 536 | u8 end; |
| @@ -580,9 +616,11 @@ static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid siz | |||
| 580 | 616 | ||
| 581 | struct DeviceInfo { | 617 | struct DeviceInfo { |
| 582 | FirmwareVersion firmware; | 618 | FirmwareVersion firmware; |
| 619 | std::array<u8, 2> unknown_1; | ||
| 583 | MacAddress mac_address; | 620 | MacAddress mac_address; |
| 621 | std::array<u8, 2> unknown_2; | ||
| 584 | }; | 622 | }; |
| 585 | static_assert(sizeof(DeviceInfo) == 0x8, "DeviceInfo is an invalid size"); | 623 | static_assert(sizeof(DeviceInfo) == 0xC, "DeviceInfo is an invalid size"); |
| 586 | 624 | ||
| 587 | struct MotionStatus { | 625 | struct MotionStatus { |
| 588 | bool is_enabled; | 626 | bool is_enabled; |
| @@ -598,6 +636,53 @@ struct RingStatus { | |||
| 598 | s16 min_value; | 636 | s16 min_value; |
| 599 | }; | 637 | }; |
| 600 | 638 | ||
| 639 | struct VibrationPacket { | ||
| 640 | OutputReport output_report; | ||
| 641 | u8 packet_counter; | ||
| 642 | std::array<u8, 0x8> vibration_data; | ||
| 643 | }; | ||
| 644 | static_assert(sizeof(VibrationPacket) == 0xA, "VibrationPacket is an invalid size"); | ||
| 645 | |||
| 646 | struct SubCommandPacket { | ||
| 647 | OutputReport output_report; | ||
| 648 | u8 packet_counter; | ||
| 649 | INSERT_PADDING_BYTES(0x8); // This contains vibration data | ||
| 650 | SubCommand sub_command; | ||
| 651 | std::array<u8, 0x26> command_data; | ||
| 652 | }; | ||
| 653 | static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size"); | ||
| 654 | |||
| 655 | #pragma pack(push, 1) | ||
| 656 | struct ReadSpiPacket { | ||
| 657 | SpiAddress spi_address; | ||
| 658 | INSERT_PADDING_BYTES(0x2); | ||
| 659 | u8 size; | ||
| 660 | }; | ||
| 661 | static_assert(sizeof(ReadSpiPacket) == 0x5, "ReadSpiPacket is an invalid size"); | ||
| 662 | |||
| 663 | struct SubCommandResponse { | ||
| 664 | InputReportPassive input_report; | ||
| 665 | SubCommand sub_command; | ||
| 666 | union { | ||
| 667 | std::array<u8, 0x30> command_data; | ||
| 668 | SpiAddress spi_address; // Reply from SPI_FLASH_READ subcommand | ||
| 669 | ExternalDeviceId external_device_id; // Reply from GET_EXTERNAL_DEVICE_INFO subcommand | ||
| 670 | DeviceInfo device_info; // Reply from REQ_DEV_INFO subcommand | ||
| 671 | }; | ||
| 672 | u8 crc; // This is never used | ||
| 673 | }; | ||
| 674 | static_assert(sizeof(SubCommandResponse) == 0x40, "SubCommandResponse is an invalid size"); | ||
| 675 | #pragma pack(pop) | ||
| 676 | |||
| 677 | struct MCUCommandResponse { | ||
| 678 | InputReportNfcIr input_report; | ||
| 679 | INSERT_PADDING_BYTES(0x8); | ||
| 680 | MCUReport mcu_report; | ||
| 681 | std::array<u8, 0x13D> mcu_data; | ||
| 682 | u8 crc; | ||
| 683 | }; | ||
| 684 | static_assert(sizeof(MCUCommandResponse) == 0x170, "MCUCommandResponse is an invalid size"); | ||
| 685 | |||
| 601 | struct JoyconCallbacks { | 686 | struct JoyconCallbacks { |
| 602 | std::function<void(Battery)> on_battery_data; | 687 | std::function<void(Battery)> on_battery_data; |
| 603 | std::function<void(Color)> on_color_data; | 688 | std::function<void(Color)> on_color_data; |
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index 5c0f71722..eeba82986 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp | |||
| @@ -110,7 +110,7 @@ bool NfcProtocol::HasAmiibo() { | |||
| 110 | 110 | ||
| 111 | DriverResult NfcProtocol::WaitUntilNfcIsReady() { | 111 | DriverResult NfcProtocol::WaitUntilNfcIsReady() { |
| 112 | constexpr std::size_t timeout_limit = 10; | 112 | constexpr std::size_t timeout_limit = 10; |
| 113 | std::vector<u8> output; | 113 | MCUCommandResponse output{}; |
| 114 | std::size_t tries = 0; | 114 | std::size_t tries = 0; |
| 115 | 115 | ||
| 116 | do { | 116 | do { |
| @@ -122,8 +122,9 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() { | |||
| 122 | if (tries++ > timeout_limit) { | 122 | if (tries++ > timeout_limit) { |
| 123 | return DriverResult::Timeout; | 123 | return DriverResult::Timeout; |
| 124 | } | 124 | } |
| 125 | } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[55] != 0x31 || | 125 | } while (output.mcu_report != MCUReport::NFCState || |
| 126 | output[56] != 0x00); | 126 | (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || |
| 127 | output.mcu_data[5] != 0x31 || output.mcu_data[6] != 0x00); | ||
| 127 | 128 | ||
| 128 | return DriverResult::Success; | 129 | return DriverResult::Success; |
| 129 | } | 130 | } |
| @@ -131,7 +132,7 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() { | |||
| 131 | DriverResult NfcProtocol::StartPolling(TagFoundData& data) { | 132 | DriverResult NfcProtocol::StartPolling(TagFoundData& data) { |
| 132 | LOG_DEBUG(Input, "Start Polling for tag"); | 133 | LOG_DEBUG(Input, "Start Polling for tag"); |
| 133 | constexpr std::size_t timeout_limit = 7; | 134 | constexpr std::size_t timeout_limit = 7; |
| 134 | std::vector<u8> output; | 135 | MCUCommandResponse output{}; |
| 135 | std::size_t tries = 0; | 136 | std::size_t tries = 0; |
| 136 | 137 | ||
| 137 | do { | 138 | do { |
| @@ -142,18 +143,20 @@ DriverResult NfcProtocol::StartPolling(TagFoundData& data) { | |||
| 142 | if (tries++ > timeout_limit) { | 143 | if (tries++ > timeout_limit) { |
| 143 | return DriverResult::Timeout; | 144 | return DriverResult::Timeout; |
| 144 | } | 145 | } |
| 145 | } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[56] != 0x09); | 146 | } while (output.mcu_report != MCUReport::NFCState || |
| 147 | (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || | ||
| 148 | output.mcu_data[6] != 0x09); | ||
| 146 | 149 | ||
| 147 | data.type = output[62]; | 150 | data.type = output.mcu_data[12]; |
| 148 | data.uuid.resize(output[64]); | 151 | data.uuid.resize(output.mcu_data[14]); |
| 149 | memcpy(data.uuid.data(), output.data() + 65, data.uuid.size()); | 152 | memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size()); |
| 150 | 153 | ||
| 151 | return DriverResult::Success; | 154 | return DriverResult::Success; |
| 152 | } | 155 | } |
| 153 | 156 | ||
| 154 | DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { | 157 | DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { |
| 155 | constexpr std::size_t timeout_limit = 10; | 158 | constexpr std::size_t timeout_limit = 10; |
| 156 | std::vector<u8> output; | 159 | MCUCommandResponse output{}; |
| 157 | std::size_t tries = 0; | 160 | std::size_t tries = 0; |
| 158 | 161 | ||
| 159 | std::string uuid_string; | 162 | std::string uuid_string; |
| @@ -168,23 +171,24 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { | |||
| 168 | // Read Tag data | 171 | // Read Tag data |
| 169 | while (true) { | 172 | while (true) { |
| 170 | auto result = SendReadAmiiboRequest(output, ntag_pages); | 173 | auto result = SendReadAmiiboRequest(output, ntag_pages); |
| 171 | const auto mcu_report = static_cast<MCUReport>(output[49]); | 174 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); |
| 172 | const auto nfc_status = static_cast<NFCStatus>(output[56]); | ||
| 173 | 175 | ||
| 174 | if (result != DriverResult::Success) { | 176 | if (result != DriverResult::Success) { |
| 175 | return result; | 177 | return result; |
| 176 | } | 178 | } |
| 177 | 179 | ||
| 178 | if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && | 180 | if ((output.mcu_report == MCUReport::NFCReadData || |
| 181 | output.mcu_report == MCUReport::NFCState) && | ||
| 179 | nfc_status == NFCStatus::TagLost) { | 182 | nfc_status == NFCStatus::TagLost) { |
| 180 | return DriverResult::ErrorReadingData; | 183 | return DriverResult::ErrorReadingData; |
| 181 | } | 184 | } |
| 182 | 185 | ||
| 183 | if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07 && output[52] == 0x01) { | 186 | if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07 && |
| 187 | output.mcu_data[2] == 0x01) { | ||
| 184 | if (data.type != 2) { | 188 | if (data.type != 2) { |
| 185 | continue; | 189 | continue; |
| 186 | } | 190 | } |
| 187 | switch (output[74]) { | 191 | switch (output.mcu_data[24]) { |
| 188 | case 0: | 192 | case 0: |
| 189 | ntag_pages = NFCPages::Block135; | 193 | ntag_pages = NFCPages::Block135; |
| 190 | break; | 194 | break; |
| @@ -200,14 +204,14 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { | |||
| 200 | continue; | 204 | continue; |
| 201 | } | 205 | } |
| 202 | 206 | ||
| 203 | if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { | 207 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { |
| 204 | // finished | 208 | // finished |
| 205 | SendStopPollingRequest(output); | 209 | SendStopPollingRequest(output); |
| 206 | return DriverResult::Success; | 210 | return DriverResult::Success; |
| 207 | } | 211 | } |
| 208 | 212 | ||
| 209 | // Ignore other state reports | 213 | // Ignore other state reports |
| 210 | if (mcu_report == MCUReport::NFCState) { | 214 | if (output.mcu_report == MCUReport::NFCState) { |
| 211 | continue; | 215 | continue; |
| 212 | } | 216 | } |
| 213 | 217 | ||
| @@ -221,7 +225,7 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { | |||
| 221 | 225 | ||
| 222 | DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { | 226 | DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { |
| 223 | constexpr std::size_t timeout_limit = 10; | 227 | constexpr std::size_t timeout_limit = 10; |
| 224 | std::vector<u8> output; | 228 | MCUCommandResponse output{}; |
| 225 | std::size_t tries = 0; | 229 | std::size_t tries = 0; |
| 226 | 230 | ||
| 227 | NFCPages ntag_pages = NFCPages::Block135; | 231 | NFCPages ntag_pages = NFCPages::Block135; |
| @@ -229,36 +233,38 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { | |||
| 229 | // Read Tag data | 233 | // Read Tag data |
| 230 | while (true) { | 234 | while (true) { |
| 231 | auto result = SendReadAmiiboRequest(output, ntag_pages); | 235 | auto result = SendReadAmiiboRequest(output, ntag_pages); |
| 232 | const auto mcu_report = static_cast<MCUReport>(output[49]); | 236 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); |
| 233 | const auto nfc_status = static_cast<NFCStatus>(output[56]); | ||
| 234 | 237 | ||
| 235 | if (result != DriverResult::Success) { | 238 | if (result != DriverResult::Success) { |
| 236 | return result; | 239 | return result; |
| 237 | } | 240 | } |
| 238 | 241 | ||
| 239 | if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && | 242 | if ((output.mcu_report == MCUReport::NFCReadData || |
| 243 | output.mcu_report == MCUReport::NFCState) && | ||
| 240 | nfc_status == NFCStatus::TagLost) { | 244 | nfc_status == NFCStatus::TagLost) { |
| 241 | return DriverResult::ErrorReadingData; | 245 | return DriverResult::ErrorReadingData; |
| 242 | } | 246 | } |
| 243 | 247 | ||
| 244 | if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07) { | 248 | if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { |
| 245 | std::size_t payload_size = (output[54] << 8 | output[55]) & 0x7FF; | 249 | std::size_t payload_size = (output.mcu_data[4] << 8 | output.mcu_data[5]) & 0x7FF; |
| 246 | if (output[52] == 0x01) { | 250 | if (output.mcu_data[2] == 0x01) { |
| 247 | memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 116, payload_size - 60); | 251 | memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 66, |
| 252 | payload_size - 60); | ||
| 248 | ntag_buffer_pos += payload_size - 60; | 253 | ntag_buffer_pos += payload_size - 60; |
| 249 | } else { | 254 | } else { |
| 250 | memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 56, payload_size); | 255 | memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 6, |
| 256 | payload_size); | ||
| 251 | } | 257 | } |
| 252 | continue; | 258 | continue; |
| 253 | } | 259 | } |
| 254 | 260 | ||
| 255 | if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { | 261 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { |
| 256 | LOG_INFO(Input, "Finished reading amiibo"); | 262 | LOG_INFO(Input, "Finished reading amiibo"); |
| 257 | return DriverResult::Success; | 263 | return DriverResult::Success; |
| 258 | } | 264 | } |
| 259 | 265 | ||
| 260 | // Ignore other state reports | 266 | // Ignore other state reports |
| 261 | if (mcu_report == MCUReport::NFCState) { | 267 | if (output.mcu_report == MCUReport::NFCState) { |
| 262 | continue; | 268 | continue; |
| 263 | } | 269 | } |
| 264 | 270 | ||
| @@ -270,7 +276,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { | |||
| 270 | return DriverResult::Success; | 276 | return DriverResult::Success; |
| 271 | } | 277 | } |
| 272 | 278 | ||
| 273 | DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) { | 279 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) { |
| 274 | NFCRequestState request{ | 280 | NFCRequestState request{ |
| 275 | .sub_command = MCUSubCommand::ReadDeviceMode, | 281 | .sub_command = MCUSubCommand::ReadDeviceMode, |
| 276 | .command_argument = NFCReadCommand::StartPolling, | 282 | .command_argument = NFCReadCommand::StartPolling, |
| @@ -294,7 +300,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) { | |||
| 294 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); | 300 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); |
| 295 | } | 301 | } |
| 296 | 302 | ||
| 297 | DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) { | 303 | DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { |
| 298 | NFCRequestState request{ | 304 | NFCRequestState request{ |
| 299 | .sub_command = MCUSubCommand::ReadDeviceMode, | 305 | .sub_command = MCUSubCommand::ReadDeviceMode, |
| 300 | .command_argument = NFCReadCommand::StopPolling, | 306 | .command_argument = NFCReadCommand::StopPolling, |
| @@ -311,7 +317,7 @@ DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) { | |||
| 311 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); | 317 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); |
| 312 | } | 318 | } |
| 313 | 319 | ||
| 314 | DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output) { | 320 | DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) { |
| 315 | NFCRequestState request{ | 321 | NFCRequestState request{ |
| 316 | .sub_command = MCUSubCommand::ReadDeviceMode, | 322 | .sub_command = MCUSubCommand::ReadDeviceMode, |
| 317 | .command_argument = NFCReadCommand::StartWaitingRecieve, | 323 | .command_argument = NFCReadCommand::StartWaitingRecieve, |
| @@ -328,7 +334,7 @@ DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output | |||
| 328 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); | 334 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); |
| 329 | } | 335 | } |
| 330 | 336 | ||
| 331 | DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages) { | 337 | DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { |
| 332 | NFCRequestState request{ | 338 | NFCRequestState request{ |
| 333 | .sub_command = MCUSubCommand::ReadDeviceMode, | 339 | .sub_command = MCUSubCommand::ReadDeviceMode, |
| 334 | .command_argument = NFCReadCommand::Ntag, | 340 | .command_argument = NFCReadCommand::Ntag, |
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index e63665aa9..11e263e07 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h | |||
| @@ -45,13 +45,13 @@ private: | |||
| 45 | 45 | ||
| 46 | DriverResult GetAmiiboData(std::vector<u8>& data); | 46 | DriverResult GetAmiiboData(std::vector<u8>& data); |
| 47 | 47 | ||
| 48 | DriverResult SendStartPollingRequest(std::vector<u8>& output); | 48 | DriverResult SendStartPollingRequest(MCUCommandResponse& output); |
| 49 | 49 | ||
| 50 | DriverResult SendStopPollingRequest(std::vector<u8>& output); | 50 | DriverResult SendStopPollingRequest(MCUCommandResponse& output); |
| 51 | 51 | ||
| 52 | DriverResult SendStartWaitingRecieveRequest(std::vector<u8>& output); | 52 | DriverResult SendStartWaitingRecieveRequest(MCUCommandResponse& output); |
| 53 | 53 | ||
| 54 | DriverResult SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages); | 54 | DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages); |
| 55 | 55 | ||
| 56 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; | 56 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; |
| 57 | 57 | ||
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index 7f8e093fa..9bb15e935 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp | |||
| @@ -31,9 +31,7 @@ void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& moti | |||
| 31 | case Joycon::ControllerType::Pro: | 31 | case Joycon::ControllerType::Pro: |
| 32 | UpdateActiveProPadInput(data, motion_status); | 32 | UpdateActiveProPadInput(data, motion_status); |
| 33 | break; | 33 | break; |
| 34 | case Joycon::ControllerType::Grip: | 34 | default: |
| 35 | case Joycon::ControllerType::Dual: | ||
| 36 | case Joycon::ControllerType::None: | ||
| 37 | break; | 35 | break; |
| 38 | } | 36 | } |
| 39 | 37 | ||
| @@ -58,9 +56,7 @@ void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) { | |||
| 58 | case Joycon::ControllerType::Pro: | 56 | case Joycon::ControllerType::Pro: |
| 59 | UpdatePasiveProPadInput(data); | 57 | UpdatePasiveProPadInput(data); |
| 60 | break; | 58 | break; |
| 61 | case Joycon::ControllerType::Grip: | 59 | default: |
| 62 | case Joycon::ControllerType::Dual: | ||
| 63 | case Joycon::ControllerType::None: | ||
| 64 | break; | 60 | break; |
| 65 | } | 61 | } |
| 66 | } | 62 | } |
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp index 12f81309e..190cef812 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.cpp +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp | |||
| @@ -70,14 +70,12 @@ DriverResult RingConProtocol::StartRingconPolling() { | |||
| 70 | DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { | 70 | DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { |
| 71 | LOG_DEBUG(Input, "IsRingConnected"); | 71 | LOG_DEBUG(Input, "IsRingConnected"); |
| 72 | constexpr std::size_t max_tries = 28; | 72 | constexpr std::size_t max_tries = 28; |
| 73 | constexpr u8 ring_controller_id = 0x20; | 73 | SubCommandResponse output{}; |
| 74 | std::vector<u8> output; | ||
| 75 | std::size_t tries = 0; | 74 | std::size_t tries = 0; |
| 76 | is_connected = false; | 75 | is_connected = false; |
| 77 | 76 | ||
| 78 | do { | 77 | do { |
| 79 | std::array<u8, 1> empty_data{}; | 78 | const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output); |
| 80 | const auto result = SendSubCommand(SubCommand::UNKNOWN_RINGCON, empty_data, output); | ||
| 81 | 79 | ||
| 82 | if (result != DriverResult::Success) { | 80 | if (result != DriverResult::Success) { |
| 83 | return result; | 81 | return result; |
| @@ -86,7 +84,7 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { | |||
| 86 | if (tries++ >= max_tries) { | 84 | if (tries++ >= max_tries) { |
| 87 | return DriverResult::NoDeviceDetected; | 85 | return DriverResult::NoDeviceDetected; |
| 88 | } | 86 | } |
| 89 | } while (output[16] != ring_controller_id); | 87 | } while (output.external_device_id != ExternalDeviceId::RingController); |
| 90 | 88 | ||
| 91 | is_connected = true; | 89 | is_connected = true; |
| 92 | return DriverResult::Success; | 90 | return DriverResult::Success; |
| @@ -100,14 +98,14 @@ DriverResult RingConProtocol::ConfigureRing() { | |||
| 100 | 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, | 98 | 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, |
| 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; | 99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; |
| 102 | 100 | ||
| 103 | const DriverResult result = SendSubCommand(SubCommand::UNKNOWN_RINGCON3, ring_config); | 101 | const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); |
| 104 | 102 | ||
| 105 | if (result != DriverResult::Success) { | 103 | if (result != DriverResult::Success) { |
| 106 | return result; | 104 | return result; |
| 107 | } | 105 | } |
| 108 | 106 | ||
| 109 | static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02}; | 107 | static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02}; |
| 110 | return SendSubCommand(SubCommand::UNKNOWN_RINGCON2, ringcon_data); | 108 | return SendSubCommand(SubCommand::ENABLE_EXTERNAL_POLLING, ringcon_data); |
| 111 | } | 109 | } |
| 112 | 110 | ||
| 113 | bool RingConProtocol::IsEnabled() const { | 111 | bool RingConProtocol::IsEnabled() const { |
diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 096c23b07..a6be6dac1 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp | |||
| @@ -15,6 +15,9 @@ public: | |||
| 15 | // do not play nicely with the theoretical maximum range. | 15 | // do not play nicely with the theoretical maximum range. |
| 16 | // Using a value one lower from the maximum emulates real stick behavior. | 16 | // Using a value one lower from the maximum emulates real stick behavior. |
| 17 | static constexpr float MAX_RANGE = 32766.0f / 32767.0f; | 17 | static constexpr float MAX_RANGE = 32766.0f / 32767.0f; |
| 18 | static constexpr float TAU = Common::PI * 2.0f; | ||
| 19 | // Use wider angle to ease the transition. | ||
| 20 | static constexpr float APERTURE = TAU * 0.15f; | ||
| 18 | 21 | ||
| 19 | using Button = std::unique_ptr<Common::Input::InputDevice>; | 22 | using Button = std::unique_ptr<Common::Input::InputDevice>; |
| 20 | 23 | ||
| @@ -61,30 +64,23 @@ public: | |||
| 61 | } | 64 | } |
| 62 | 65 | ||
| 63 | bool IsAngleGreater(float old_angle, float new_angle) const { | 66 | bool IsAngleGreater(float old_angle, float new_angle) const { |
| 64 | constexpr float TAU = Common::PI * 2.0f; | 67 | const float top_limit = new_angle + APERTURE; |
| 65 | // Use wider angle to ease the transition. | ||
| 66 | constexpr float aperture = TAU * 0.15f; | ||
| 67 | const float top_limit = new_angle + aperture; | ||
| 68 | return (old_angle > new_angle && old_angle <= top_limit) || | 68 | return (old_angle > new_angle && old_angle <= top_limit) || |
| 69 | (old_angle + TAU > new_angle && old_angle + TAU <= top_limit); | 69 | (old_angle + TAU > new_angle && old_angle + TAU <= top_limit); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | bool IsAngleSmaller(float old_angle, float new_angle) const { | 72 | bool IsAngleSmaller(float old_angle, float new_angle) const { |
| 73 | constexpr float TAU = Common::PI * 2.0f; | 73 | const float bottom_limit = new_angle - APERTURE; |
| 74 | // Use wider angle to ease the transition. | ||
| 75 | constexpr float aperture = TAU * 0.15f; | ||
| 76 | const float bottom_limit = new_angle - aperture; | ||
| 77 | return (old_angle >= bottom_limit && old_angle < new_angle) || | 74 | return (old_angle >= bottom_limit && old_angle < new_angle) || |
| 78 | (old_angle - TAU >= bottom_limit && old_angle - TAU < new_angle); | 75 | (old_angle - TAU >= bottom_limit && old_angle - TAU < new_angle); |
| 79 | } | 76 | } |
| 80 | 77 | ||
| 81 | float GetAngle(std::chrono::time_point<std::chrono::steady_clock> now) const { | 78 | float GetAngle(std::chrono::time_point<std::chrono::steady_clock> now) const { |
| 82 | constexpr float TAU = Common::PI * 2.0f; | ||
| 83 | float new_angle = angle; | 79 | float new_angle = angle; |
| 84 | 80 | ||
| 85 | auto time_difference = static_cast<float>( | 81 | auto time_difference = static_cast<float>( |
| 86 | std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count()); | 82 | std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update).count()); |
| 87 | time_difference /= 1000.0f * 1000.0f; | 83 | time_difference /= 1000.0f; |
| 88 | if (time_difference > 0.5f) { | 84 | if (time_difference > 0.5f) { |
| 89 | time_difference = 0.5f; | 85 | time_difference = 0.5f; |
| 90 | } | 86 | } |
| @@ -201,8 +197,6 @@ public: | |||
| 201 | } | 197 | } |
| 202 | 198 | ||
| 203 | void UpdateStatus() { | 199 | void UpdateStatus() { |
| 204 | const float coef = modifier_status.value ? modifier_scale : MAX_RANGE; | ||
| 205 | |||
| 206 | bool r = right_status; | 200 | bool r = right_status; |
| 207 | bool l = left_status; | 201 | bool l = left_status; |
| 208 | bool u = up_status; | 202 | bool u = up_status; |
| @@ -220,7 +214,7 @@ public: | |||
| 220 | 214 | ||
| 221 | // Move if a key is pressed | 215 | // Move if a key is pressed |
| 222 | if (r || l || u || d) { | 216 | if (r || l || u || d) { |
| 223 | amplitude = coef; | 217 | amplitude = modifier_status.value ? modifier_scale : MAX_RANGE; |
| 224 | } else { | 218 | } else { |
| 225 | amplitude = 0; | 219 | amplitude = 0; |
| 226 | } | 220 | } |
| @@ -274,30 +268,17 @@ public: | |||
| 274 | Common::Input::StickStatus status{}; | 268 | Common::Input::StickStatus status{}; |
| 275 | status.x.properties = properties; | 269 | status.x.properties = properties; |
| 276 | status.y.properties = properties; | 270 | status.y.properties = properties; |
| 271 | |||
| 277 | if (Settings::values.emulate_analog_keyboard) { | 272 | if (Settings::values.emulate_analog_keyboard) { |
| 278 | const auto now = std::chrono::steady_clock::now(); | 273 | const auto now = std::chrono::steady_clock::now(); |
| 279 | float angle_ = GetAngle(now); | 274 | const float angle_ = GetAngle(now); |
| 280 | status.x.raw_value = std::cos(angle_) * amplitude; | 275 | status.x.raw_value = std::cos(angle_) * amplitude; |
| 281 | status.y.raw_value = std::sin(angle_) * amplitude; | 276 | status.y.raw_value = std::sin(angle_) * amplitude; |
| 282 | return status; | 277 | return status; |
| 283 | } | 278 | } |
| 284 | constexpr float SQRT_HALF = 0.707106781f; | 279 | |
| 285 | int x = 0, y = 0; | 280 | status.x.raw_value = std::cos(goal_angle) * amplitude; |
| 286 | if (right_status) { | 281 | status.y.raw_value = std::sin(goal_angle) * amplitude; |
| 287 | ++x; | ||
| 288 | } | ||
| 289 | if (left_status) { | ||
| 290 | --x; | ||
| 291 | } | ||
| 292 | if (up_status) { | ||
| 293 | ++y; | ||
| 294 | } | ||
| 295 | if (down_status) { | ||
| 296 | --y; | ||
| 297 | } | ||
| 298 | const float coef = modifier_status.value ? modifier_scale : MAX_RANGE; | ||
| 299 | status.x.raw_value = static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF); | ||
| 300 | status.y.raw_value = static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF); | ||
| 301 | return status; | 282 | return status; |
| 302 | } | 283 | } |
| 303 | 284 | ||
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 15cbf7e5f..8c6a6521a 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp | |||
| @@ -16,10 +16,10 @@ public: | |||
| 16 | 16 | ||
| 17 | class InputFromButton final : public Common::Input::InputDevice { | 17 | class InputFromButton final : public Common::Input::InputDevice { |
| 18 | public: | 18 | public: |
| 19 | explicit InputFromButton(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, | 19 | explicit InputFromButton(PadIdentifier identifier_, int button_, bool turbo_, bool toggle_, |
| 20 | InputEngine* input_engine_) | 20 | bool inverted_, InputEngine* input_engine_) |
| 21 | : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), | 21 | : identifier(identifier_), button(button_), turbo(turbo_), toggle(toggle_), |
| 22 | input_engine(input_engine_) { | 22 | inverted(inverted_), input_engine(input_engine_) { |
| 23 | UpdateCallback engine_callback{[this]() { OnChange(); }}; | 23 | UpdateCallback engine_callback{[this]() { OnChange(); }}; |
| 24 | const InputIdentifier input_identifier{ | 24 | const InputIdentifier input_identifier{ |
| 25 | .identifier = identifier, | 25 | .identifier = identifier, |
| @@ -40,6 +40,7 @@ public: | |||
| 40 | .value = input_engine->GetButton(identifier, button), | 40 | .value = input_engine->GetButton(identifier, button), |
| 41 | .inverted = inverted, | 41 | .inverted = inverted, |
| 42 | .toggle = toggle, | 42 | .toggle = toggle, |
| 43 | .turbo = turbo, | ||
| 43 | }; | 44 | }; |
| 44 | } | 45 | } |
| 45 | 46 | ||
| @@ -68,6 +69,7 @@ public: | |||
| 68 | private: | 69 | private: |
| 69 | const PadIdentifier identifier; | 70 | const PadIdentifier identifier; |
| 70 | const int button; | 71 | const int button; |
| 72 | const bool turbo; | ||
| 71 | const bool toggle; | 73 | const bool toggle; |
| 72 | const bool inverted; | 74 | const bool inverted; |
| 73 | int callback_key; | 75 | int callback_key; |
| @@ -77,10 +79,10 @@ private: | |||
| 77 | 79 | ||
| 78 | class InputFromHatButton final : public Common::Input::InputDevice { | 80 | class InputFromHatButton final : public Common::Input::InputDevice { |
| 79 | public: | 81 | public: |
| 80 | explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool toggle_, | 82 | explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool turbo_, |
| 81 | bool inverted_, InputEngine* input_engine_) | 83 | bool toggle_, bool inverted_, InputEngine* input_engine_) |
| 82 | : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_), | 84 | : identifier(identifier_), button(button_), direction(direction_), turbo(turbo_), |
| 83 | inverted(inverted_), input_engine(input_engine_) { | 85 | toggle(toggle_), inverted(inverted_), input_engine(input_engine_) { |
| 84 | UpdateCallback engine_callback{[this]() { OnChange(); }}; | 86 | UpdateCallback engine_callback{[this]() { OnChange(); }}; |
| 85 | const InputIdentifier input_identifier{ | 87 | const InputIdentifier input_identifier{ |
| 86 | .identifier = identifier, | 88 | .identifier = identifier, |
| @@ -101,6 +103,7 @@ public: | |||
| 101 | .value = input_engine->GetHatButton(identifier, button, direction), | 103 | .value = input_engine->GetHatButton(identifier, button, direction), |
| 102 | .inverted = inverted, | 104 | .inverted = inverted, |
| 103 | .toggle = toggle, | 105 | .toggle = toggle, |
| 106 | .turbo = turbo, | ||
| 104 | }; | 107 | }; |
| 105 | } | 108 | } |
| 106 | 109 | ||
| @@ -130,6 +133,7 @@ private: | |||
| 130 | const PadIdentifier identifier; | 133 | const PadIdentifier identifier; |
| 131 | const int button; | 134 | const int button; |
| 132 | const u8 direction; | 135 | const u8 direction; |
| 136 | const bool turbo; | ||
| 133 | const bool toggle; | 137 | const bool toggle; |
| 134 | const bool inverted; | 138 | const bool inverted; |
| 135 | int callback_key; | 139 | int callback_key; |
| @@ -853,14 +857,15 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice( | |||
| 853 | const auto keyboard_key = params.Get("code", 0); | 857 | const auto keyboard_key = params.Get("code", 0); |
| 854 | const auto toggle = params.Get("toggle", false) != 0; | 858 | const auto toggle = params.Get("toggle", false) != 0; |
| 855 | const auto inverted = params.Get("inverted", false) != 0; | 859 | const auto inverted = params.Get("inverted", false) != 0; |
| 860 | const auto turbo = params.Get("turbo", false) != 0; | ||
| 856 | input_engine->PreSetController(identifier); | 861 | input_engine->PreSetController(identifier); |
| 857 | input_engine->PreSetButton(identifier, button_id); | 862 | input_engine->PreSetButton(identifier, button_id); |
| 858 | input_engine->PreSetButton(identifier, keyboard_key); | 863 | input_engine->PreSetButton(identifier, keyboard_key); |
| 859 | if (keyboard_key != 0) { | 864 | if (keyboard_key != 0) { |
| 860 | return std::make_unique<InputFromButton>(identifier, keyboard_key, toggle, inverted, | 865 | return std::make_unique<InputFromButton>(identifier, keyboard_key, turbo, toggle, inverted, |
| 861 | input_engine.get()); | 866 | input_engine.get()); |
| 862 | } | 867 | } |
| 863 | return std::make_unique<InputFromButton>(identifier, button_id, toggle, inverted, | 868 | return std::make_unique<InputFromButton>(identifier, button_id, turbo, toggle, inverted, |
| 864 | input_engine.get()); | 869 | input_engine.get()); |
| 865 | } | 870 | } |
| 866 | 871 | ||
| @@ -876,11 +881,12 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice( | |||
| 876 | const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); | 881 | const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); |
| 877 | const auto toggle = params.Get("toggle", false) != 0; | 882 | const auto toggle = params.Get("toggle", false) != 0; |
| 878 | const auto inverted = params.Get("inverted", false) != 0; | 883 | const auto inverted = params.Get("inverted", false) != 0; |
| 884 | const auto turbo = params.Get("turbo", false) != 0; | ||
| 879 | 885 | ||
| 880 | input_engine->PreSetController(identifier); | 886 | input_engine->PreSetController(identifier); |
| 881 | input_engine->PreSetHatButton(identifier, button_id); | 887 | input_engine->PreSetHatButton(identifier, button_id); |
| 882 | return std::make_unique<InputFromHatButton>(identifier, button_id, direction, toggle, inverted, | 888 | return std::make_unique<InputFromHatButton>(identifier, button_id, direction, turbo, toggle, |
| 883 | input_engine.get()); | 889 | inverted, input_engine.get()); |
| 884 | } | 890 | } |
| 885 | 891 | ||
| 886 | std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateStickDevice( | 892 | std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateStickDevice( |