summaryrefslogtreecommitdiff
path: root/src/input_common/helpers/joycon_protocol/common_protocol.cpp
diff options
context:
space:
mode:
authorGravatar liamwhite2023-01-30 09:02:12 -0500
committerGravatar GitHub2023-01-30 09:02:12 -0500
commite74660673b68e7226b7e934efe5eac620f7a98e6 (patch)
tree355def233607668733581b2b5194d0e54e1b7995 /src/input_common/helpers/joycon_protocol/common_protocol.cpp
parentMerge pull request #9631 from vonchenplus/vulkan_clear (diff)
parentinput_common: joycon: Remove Magic numbers from common protocol (diff)
downloadyuzu-e74660673b68e7226b7e934efe5eac620f7a98e6.tar.gz
yuzu-e74660673b68e7226b7e934efe5eac620f7a98e6.tar.xz
yuzu-e74660673b68e7226b7e934efe5eac620f7a98e6.zip
Merge pull request #9701 from german77/common_protocol
input_common: joycon: Remove Magic numbers from common protocol
Diffstat (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp')
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp155
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
24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { 24DriverResult 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
40DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { 37DriverResult 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
65DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { 63DriverResult 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
75DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vector<u8>& output) { 73DriverResult 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
100DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, 95DriverResult 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
122DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { 121DriverResult 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
127DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { 126DriverResult 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
140DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { 143DriverResult 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
151DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { 159DriverResult 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
207DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, 217DriverResult 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
233DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, 239DriverResult 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
256DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { 266DriverResult 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}