summaryrefslogtreecommitdiff
path: root/src/input_common/helpers/joycon_protocol/common_protocol.cpp
diff options
context:
space:
mode:
authorGravatar liamwhite2023-06-29 10:01:19 -0400
committerGravatar GitHub2023-06-29 10:01:19 -0400
commit4c705db73edfa3c7210eb5821b3f4e5324d642d1 (patch)
tree470116d2d52b3a74ad0cd761304f0f65386af708 /src/input_common/helpers/joycon_protocol/common_protocol.cpp
parentMerge pull request #10946 from goldenx86/amdBlending (diff)
parentinput_common: Allow timeouts to happen while scanning for a ring (diff)
downloadyuzu-4c705db73edfa3c7210eb5821b3f4e5324d642d1.tar.gz
yuzu-4c705db73edfa3c7210eb5821b3f4e5324d642d1.tar.xz
yuzu-4c705db73edfa3c7210eb5821b3f4e5324d642d1.zip
Merge pull request #10937 from german77/ring
input_common: Remove duplicated enum and fix ring detection
Diffstat (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp')
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp104
1 files changed, 56 insertions, 48 deletions
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 88f4cec1c..a6eecf980 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/common_protocol.h" 6#include "input_common/helpers/joycon_protocol/common_protocol.h"
6 7
@@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() {
21 SDL_hid_set_nonblocking(hidapi_handle->handle, 1); 22 SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
22} 23}
23 24
24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { 25Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
25 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); 26 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
26 27
27 if (result == DriverResult::Success) { 28 if (result == Common::Input::DriverResult::Success) {
28 // Fallback to 3rd party pro controllers 29 // Fallback to 3rd party pro controllers
29 if (controller_type == ControllerType::None) { 30 if (controller_type == ControllerType::None) {
30 controller_type = ControllerType::Pro; 31 controller_type = ControllerType::Pro;
@@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
34 return result; 35 return result;
35} 36}
36 37
37DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { 38Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(
39 SDL_hid_device_info* device_info) {
38 ControllerType controller_type{ControllerType::None}; 40 ControllerType controller_type{ControllerType::None};
39 const auto result = GetDeviceType(controller_type); 41 const auto result = GetDeviceType(controller_type);
40 42
41 if (result != DriverResult::Success || controller_type == ControllerType::None) { 43 if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) {
42 return DriverResult::UnsupportedControllerType; 44 return Common::Input::DriverResult::UnsupportedControllerType;
43 } 45 }
44 46
45 hidapi_handle->handle = 47 hidapi_handle->handle =
@@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device
48 if (!hidapi_handle->handle) { 50 if (!hidapi_handle->handle) {
49 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", 51 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
50 device_info->vendor_id, device_info->product_id); 52 device_info->vendor_id, device_info->product_id);
51 return DriverResult::HandleInUse; 53 return Common::Input::DriverResult::HandleInUse;
52 } 54 }
53 55
54 SetNonBlocking(); 56 SetNonBlocking();
55 return DriverResult::Success; 57 return Common::Input::DriverResult::Success;
56} 58}
57 59
58DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { 60Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
59 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)}; 61 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)};
60 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); 62 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
61} 63}
62 64
63DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { 65Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
64 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); 66 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
65 67
66 if (result == -1) { 68 if (result == -1) {
67 return DriverResult::ErrorWritingData; 69 return Common::Input::DriverResult::ErrorWritingData;
68 } 70 }
69 71
70 return DriverResult::Success; 72 return Common::Input::DriverResult::Success;
71} 73}
72 74
73DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, 75Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(
74 SubCommandResponse& output) { 76 SubCommand sc, SubCommandResponse& output) {
75 constexpr int timeout_mili = 66; 77 constexpr int timeout_mili = 66;
76 constexpr int MaxTries = 3; 78 constexpr int MaxTries = 10;
77 int tries = 0; 79 int tries = 0;
78 80
79 do { 81 do {
@@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
84 LOG_ERROR(Input, "No response from joycon"); 86 LOG_ERROR(Input, "No response from joycon");
85 } 87 }
86 if (tries++ > MaxTries) { 88 if (tries++ > MaxTries) {
87 return DriverResult::Timeout; 89 return Common::Input::DriverResult::Timeout;
88 } 90 }
89 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && 91 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
90 output.sub_command != sc); 92 output.sub_command != sc);
91 93
92 return DriverResult::Success; 94 return Common::Input::DriverResult::Success;
93} 95}
94 96
95DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, 97Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
96 SubCommandResponse& output) { 98 std::span<const u8> buffer,
99 SubCommandResponse& output) {
97 SubCommandPacket packet{ 100 SubCommandPacket packet{
98 .output_report = OutputReport::RUMBLE_AND_SUBCMD, 101 .output_report = OutputReport::RUMBLE_AND_SUBCMD,
99 .packet_counter = GetCounter(), 102 .packet_counter = GetCounter(),
@@ -102,26 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
102 }; 105 };
103 106
104 if (buffer.size() > packet.command_data.size()) { 107 if (buffer.size() > packet.command_data.size()) {
105 return DriverResult::InvalidParameters; 108 return Common::Input::DriverResult::InvalidParameters;
106 } 109 }
107 110
108 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 111 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
109 112
110 auto result = SendData(packet); 113 auto result = SendData(packet);
111 114
112 if (result != DriverResult::Success) { 115 if (result != Common::Input::DriverResult::Success) {
113 return result; 116 return result;
114 } 117 }
115 118
116 return GetSubCommandResponse(sc, output); 119 return GetSubCommandResponse(sc, output);
117} 120}
118 121
119DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { 122Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
123 std::span<const u8> buffer) {
120 SubCommandResponse output{}; 124 SubCommandResponse output{};
121 return SendSubCommand(sc, buffer, output); 125 return SendSubCommand(sc, buffer, output);
122} 126}
123 127
124DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { 128Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc,
129 std::span<const u8> buffer) {
125 SubCommandPacket packet{ 130 SubCommandPacket packet{
126 .output_report = OutputReport::MCU_DATA, 131 .output_report = OutputReport::MCU_DATA,
127 .packet_counter = GetCounter(), 132 .packet_counter = GetCounter(),
@@ -130,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
130 }; 135 };
131 136
132 if (buffer.size() > packet.command_data.size()) { 137 if (buffer.size() > packet.command_data.size()) {
133 return DriverResult::InvalidParameters; 138 return Common::Input::DriverResult::InvalidParameters;
134 } 139 }
135 140
136 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 141 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
@@ -138,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
138 return SendData(packet); 143 return SendData(packet);
139} 144}
140 145
141DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { 146Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
142 VibrationPacket packet{ 147 VibrationPacket packet{
143 .output_report = OutputReport::RUMBLE_ONLY, 148 .output_report = OutputReport::RUMBLE_ONLY,
144 .packet_counter = GetCounter(), 149 .packet_counter = GetCounter(),
@@ -146,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
146 }; 151 };
147 152
148 if (buffer.size() > packet.vibration_data.size()) { 153 if (buffer.size() > packet.vibration_data.size()) {
149 return DriverResult::InvalidParameters; 154 return Common::Input::DriverResult::InvalidParameters;
150 } 155 }
151 156
152 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); 157 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
@@ -154,7 +159,8 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
154 return SendData(packet); 159 return SendData(packet);
155} 160}
156 161
157DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { 162Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr,
163 std::span<u8> output) {
158 constexpr std::size_t HeaderSize = 5; 164 constexpr std::size_t HeaderSize = 5;
159 constexpr std::size_t MaxTries = 5; 165 constexpr std::size_t MaxTries = 5;
160 std::size_t tries = 0; 166 std::size_t tries = 0;
@@ -168,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
168 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); 174 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
169 do { 175 do {
170 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); 176 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
171 if (result != DriverResult::Success) { 177 if (result != Common::Input::DriverResult::Success) {
172 return result; 178 return result;
173 } 179 }
174 180
175 if (tries++ > MaxTries) { 181 if (tries++ > MaxTries) {
176 return DriverResult::Timeout; 182 return Common::Input::DriverResult::Timeout;
177 } 183 }
178 } while (response.spi_address != addr); 184 } while (response.spi_address != addr);
179 185
180 if (response.command_data.size() < packet_data.size + HeaderSize) { 186 if (response.command_data.size() < packet_data.size + HeaderSize) {
181 return DriverResult::WrongReply; 187 return Common::Input::DriverResult::WrongReply;
182 } 188 }
183 189
184 // Remove header from output 190 // Remove header from output
185 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); 191 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
186 return DriverResult::Success; 192 return Common::Input::DriverResult::Success;
187} 193}
188 194
189DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { 195Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
190 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)}; 196 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)};
191 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); 197 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
192 198
193 if (result != DriverResult::Success) { 199 if (result != Common::Input::DriverResult::Success) {
194 LOG_ERROR(Input, "Failed with error {}", result); 200 LOG_ERROR(Input, "Failed with error {}", result);
195 } 201 }
196 202
197 return result; 203 return result;
198} 204}
199 205
200DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { 206Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
201 LOG_DEBUG(Input, "ConfigureMCU"); 207 LOG_DEBUG(Input, "ConfigureMCU");
202 std::array<u8, sizeof(MCUConfig)> config_buffer; 208 std::array<u8, sizeof(MCUConfig)> config_buffer;
203 memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); 209 memcpy(config_buffer.data(), &config, sizeof(MCUConfig));
@@ -205,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
205 211
206 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); 212 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
207 213
208 if (result != DriverResult::Success) { 214 if (result != Common::Input::DriverResult::Success) {
209 LOG_ERROR(Input, "Failed with error {}", result); 215 LOG_ERROR(Input, "Failed with error {}", result);
210 } 216 }
211 217
212 return result; 218 return result;
213} 219}
214 220
215DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, 221Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
216 MCUCommandResponse& output) { 222 MCUCommandResponse& output) {
217 constexpr int TimeoutMili = 200; 223 constexpr int TimeoutMili = 200;
218 constexpr int MaxTries = 9; 224 constexpr int MaxTries = 9;
219 int tries = 0; 225 int tries = 0;
@@ -226,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
226 LOG_ERROR(Input, "No response from joycon attempt {}", tries); 232 LOG_ERROR(Input, "No response from joycon attempt {}", tries);
227 } 233 }
228 if (tries++ > MaxTries) { 234 if (tries++ > MaxTries) {
229 return DriverResult::Timeout; 235 return Common::Input::DriverResult::Timeout;
230 } 236 }
231 } while (output.input_report.report_mode != report_mode || 237 } while (output.input_report.report_mode != report_mode ||
232 output.mcu_report == MCUReport::EmptyAwaitingCmd); 238 output.mcu_report == MCUReport::EmptyAwaitingCmd);
233 239
234 return DriverResult::Success; 240 return Common::Input::DriverResult::Success;
235} 241}
236 242
237DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc, 243Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode,
238 std::span<const u8> buffer, 244 MCUSubCommand sc,
239 MCUCommandResponse& output) { 245 std::span<const u8> buffer,
246 MCUCommandResponse& output) {
240 SubCommandPacket packet{ 247 SubCommandPacket packet{
241 .output_report = OutputReport::MCU_DATA, 248 .output_report = OutputReport::MCU_DATA,
242 .packet_counter = GetCounter(), 249 .packet_counter = GetCounter(),
@@ -245,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom
245 }; 252 };
246 253
247 if (buffer.size() > packet.command_data.size()) { 254 if (buffer.size() > packet.command_data.size()) {
248 return DriverResult::InvalidParameters; 255 return Common::Input::DriverResult::InvalidParameters;
249 } 256 }
250 257
251 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 258 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
252 259
253 auto result = SendData(packet); 260 auto result = SendData(packet);
254 261
255 if (result != DriverResult::Success) { 262 if (result != Common::Input::DriverResult::Success) {
256 return result; 263 return result;
257 } 264 }
258 265
259 result = GetMCUDataResponse(report_mode, output); 266 result = GetMCUDataResponse(report_mode, output);
260 267
261 return DriverResult::Success; 268 return Common::Input::DriverResult::Success;
262} 269}
263 270
264DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { 271Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode,
272 MCUMode mode) {
265 MCUCommandResponse output{}; 273 MCUCommandResponse output{};
266 constexpr std::size_t MaxTries{16}; 274 constexpr std::size_t MaxTries{16};
267 std::size_t tries{}; 275 std::size_t tries{};
@@ -269,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
269 do { 277 do {
270 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output); 278 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
271 279
272 if (result != DriverResult::Success) { 280 if (result != Common::Input::DriverResult::Success) {
273 return result; 281 return result;
274 } 282 }
275 283
276 if (tries++ > MaxTries) { 284 if (tries++ > MaxTries) {
277 return DriverResult::WrongReply; 285 return Common::Input::DriverResult::WrongReply;
278 } 286 }
279 } while (output.mcu_report != MCUReport::StateReport || 287 } while (output.mcu_report != MCUReport::StateReport ||
280 output.mcu_data[6] != static_cast<u8>(mode)); 288 output.mcu_data[6] != static_cast<u8>(mode));
281 289
282 return DriverResult::Success; 290 return Common::Input::DriverResult::Success;
283} 291}
284 292
285// crc-8-ccitt / polynomial 0x07 look up table 293// crc-8-ccitt / polynomial 0x07 look up table