diff options
Diffstat (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp')
| -rw-r--r-- | src/input_common/helpers/joycon_protocol/common_protocol.cpp | 155 |
1 files changed, 83 insertions, 72 deletions
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 0ef240344..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::array<u8, 1> buffer{}; | 25 | const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); |
| 26 | const auto result = ReadRawSPI(SpiAddress::DEVICE_TYPE, 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,46 +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::ReadRawSPI(SpiAddress addr, std::span<u8> output) { | 159 | DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { |
| 152 | constexpr std::size_t HeaderSize = 20; | 160 | constexpr std::size_t HeaderSize = 5; |
| 153 | constexpr std::size_t MaxTries = 10; | 161 | constexpr std::size_t MaxTries = 10; |
| 154 | const auto size = output.size(); | ||
| 155 | std::size_t tries = 0; | 162 | std::size_t tries = 0; |
| 156 | std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, static_cast<u8>(size)}; | 163 | SubCommandResponse response{}; |
| 157 | std::vector<u8> local_buffer{}; | 164 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; |
| 158 | 165 | const ReadSpiPacket packet_data{ | |
| 159 | buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); | 166 | .spi_address = addr, |
| 160 | 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)); | ||
| 161 | do { | 171 | do { |
| 162 | const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, local_buffer); | 172 | const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); |
| 163 | if (result != DriverResult::Success) { | 173 | if (result != DriverResult::Success) { |
| 164 | return result; | 174 | return result; |
| 165 | } | 175 | } |
| @@ -167,14 +177,14 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out | |||
| 167 | if (tries++ > MaxTries) { | 177 | if (tries++ > MaxTries) { |
| 168 | return DriverResult::Timeout; | 178 | return DriverResult::Timeout; |
| 169 | } | 179 | } |
| 170 | } while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]); | 180 | } while (response.spi_address != addr); |
| 171 | 181 | ||
| 172 | if (local_buffer.size() < size + HeaderSize) { | 182 | if (response.command_data.size() < packet_data.size + HeaderSize) { |
| 173 | return DriverResult::WrongReply; | 183 | return DriverResult::WrongReply; |
| 174 | } | 184 | } |
| 175 | 185 | ||
| 176 | // Remove header from output | 186 | // Remove header from output |
| 177 | memcpy(output.data(), local_buffer.data() + HeaderSize, size); | 187 | memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); |
| 178 | return DriverResult::Success; | 188 | return DriverResult::Success; |
| 179 | } | 189 | } |
| 180 | 190 | ||
| @@ -183,7 +193,7 @@ DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { | |||
| 183 | const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); | 193 | const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); |
| 184 | 194 | ||
| 185 | if (result != DriverResult::Success) { | 195 | if (result != DriverResult::Success) { |
| 186 | LOG_ERROR(Input, "SendMCUData failed with error {}", result); | 196 | LOG_ERROR(Input, "Failed with error {}", result); |
| 187 | } | 197 | } |
| 188 | 198 | ||
| 189 | return result; | 199 | return result; |
| @@ -198,22 +208,21 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { | |||
| 198 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); | 208 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); |
| 199 | 209 | ||
| 200 | if (result != DriverResult::Success) { | 210 | if (result != DriverResult::Success) { |
| 201 | LOG_ERROR(Input, "Set MCU config failed with error {}", result); | 211 | LOG_ERROR(Input, "Failed with error {}", result); |
| 202 | } | 212 | } |
| 203 | 213 | ||
| 204 | return result; | 214 | return result; |
| 205 | } | 215 | } |
| 206 | 216 | ||
| 207 | DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, | 217 | DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, |
| 208 | std::vector<u8>& output) { | 218 | MCUCommandResponse& output) { |
| 209 | const int report_mode = static_cast<u8>(report_mode_); | ||
| 210 | constexpr int TimeoutMili = 200; | 219 | constexpr int TimeoutMili = 200; |
| 211 | constexpr int MaxTries = 9; | 220 | constexpr int MaxTries = 9; |
| 212 | int tries = 0; | 221 | int tries = 0; |
| 213 | output.resize(0x170); | ||
| 214 | 222 | ||
| 215 | do { | 223 | do { |
| 216 | 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); | ||
| 217 | 226 | ||
| 218 | if (result < 1) { | 227 | if (result < 1) { |
| 219 | LOG_ERROR(Input, "No response from joycon attempt {}", tries); | 228 | LOG_ERROR(Input, "No response from joycon attempt {}", tries); |
| @@ -221,28 +230,29 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, | |||
| 221 | if (tries++ > MaxTries) { | 230 | if (tries++ > MaxTries) { |
| 222 | return DriverResult::Timeout; | 231 | return DriverResult::Timeout; |
| 223 | } | 232 | } |
| 224 | } while (output[0] != report_mode || output[49] == 0xFF); | 233 | } while (output.input_report.report_mode != report_mode || |
| 225 | 234 | output.mcu_report == MCUReport::EmptyAwaitingCmd); | |
| 226 | if (output[0] != report_mode || output[49] == 0xFF) { | ||
| 227 | return DriverResult::WrongReply; | ||
| 228 | } | ||
| 229 | 235 | ||
| 230 | return DriverResult::Success; | 236 | return DriverResult::Success; |
| 231 | } | 237 | } |
| 232 | 238 | ||
| 233 | DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, | 239 | DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, |
| 234 | std::span<const u8> buffer, | 240 | std::span<const u8> buffer, |
| 235 | std::vector<u8>& output) { | 241 | MCUCommandResponse& output) { |
| 236 | std::vector<u8> local_buffer(MaxResponseSize); | 242 | SubCommandPacket packet{ |
| 237 | 243 | .output_report = OutputReport::MCU_DATA, | |
| 238 | local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); | 244 | .packet_counter = GetCounter(), |
| 239 | local_buffer[1] = GetCounter(); | 245 | .sub_command = sc, |
| 240 | local_buffer[9] = static_cast<u8>(sc); | 246 | .command_data = {}, |
| 241 | for (std::size_t i = 0; i < buffer.size(); ++i) { | 247 | }; |
| 242 | local_buffer[10 + i] = buffer[i]; | 248 | |
| 249 | if (buffer.size() > packet.command_data.size()) { | ||
| 250 | return DriverResult::InvalidParameters; | ||
| 243 | } | 251 | } |
| 244 | 252 | ||
| 245 | auto result = SendData(local_buffer); | 253 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); |
| 254 | |||
| 255 | auto result = SendData(packet); | ||
| 246 | 256 | ||
| 247 | if (result != DriverResult::Success) { | 257 | if (result != DriverResult::Success) { |
| 248 | return result; | 258 | return result; |
| @@ -254,7 +264,7 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubComman | |||
| 254 | } | 264 | } |
| 255 | 265 | ||
| 256 | DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { | 266 | DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { |
| 257 | std::vector<u8> output; | 267 | MCUCommandResponse output{}; |
| 258 | constexpr std::size_t MaxTries{8}; | 268 | constexpr std::size_t MaxTries{8}; |
| 259 | std::size_t tries{}; | 269 | std::size_t tries{}; |
| 260 | 270 | ||
| @@ -269,7 +279,8 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod | |||
| 269 | if (tries++ > MaxTries) { | 279 | if (tries++ > MaxTries) { |
| 270 | return DriverResult::WrongReply; | 280 | return DriverResult::WrongReply; |
| 271 | } | 281 | } |
| 272 | } 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)); | ||
| 273 | 284 | ||
| 274 | return DriverResult::Success; | 285 | return DriverResult::Success; |
| 275 | } | 286 | } |