summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/input_common/drivers/joycon.cpp4
-rw-r--r--src/input_common/drivers/joycon.h2
-rw-r--r--src/input_common/helpers/joycon_driver.cpp18
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp155
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h31
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp4
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp13
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h136
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp68
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h8
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.cpp8
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.cpp12
12 files changed, 269 insertions, 190 deletions
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
index cedc94e63..4fcfb4510 100644
--- a/src/input_common/drivers/joycon.cpp
+++ b/src/input_common/drivers/joycon.cpp
@@ -668,12 +668,10 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
668 return "Right Joycon"; 668 return "Right Joycon";
669 case Joycon::ControllerType::Pro: 669 case Joycon::ControllerType::Pro:
670 return "Pro Controller"; 670 return "Pro Controller";
671 case Joycon::ControllerType::Grip:
672 return "Grip Controller";
673 case Joycon::ControllerType::Dual: 671 case Joycon::ControllerType::Dual:
674 return "Dual Joycon"; 672 return "Dual Joycon";
675 default: 673 default:
676 return "Unknown Joycon"; 674 return "Unknown Switch Controller";
677 } 675 }
678} 676}
679} // 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>;
15struct Battery; 15struct Battery;
16struct Color; 16struct Color;
17struct MotionData; 17struct MotionData;
18enum class ControllerType; 18enum class ControllerType : u8;
19enum class DriverResult; 19enum class DriverResult;
20enum class IrsResolution; 20enum class IrsResolution;
21class JoyconDriver; 21class JoyconDriver;
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index 3775e2d35..8f94c9f45 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -162,14 +162,14 @@ void JoyconDriver::InputThread(std::stop_token stop_token) {
162} 162}
163 163
164void JoyconDriver::OnNewData(std::span<u8> buffer) { 164void JoyconDriver::OnNewData(std::span<u8> buffer) {
165 const auto report_mode = static_cast<InputReport>(buffer[0]); 165 const auto report_mode = static_cast<ReportMode>(buffer[0]);
166 166
167 // 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
168 // experience 168 // experience
169 switch (report_mode) { 169 switch (report_mode) {
170 case InputReport::STANDARD_FULL_60HZ: 170 case ReportMode::STANDARD_FULL_60HZ:
171 case InputReport::NFC_IR_MODE_60HZ: 171 case ReportMode::NFC_IR_MODE_60HZ:
172 case InputReport::SIMPLE_HID_MODE: { 172 case ReportMode::SIMPLE_HID_MODE: {
173 const auto now = std::chrono::steady_clock::now(); 173 const auto now = std::chrono::steady_clock::now();
174 const auto new_delta_time = static_cast<u64>( 174 const auto new_delta_time = static_cast<u64>(
175 std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count()); 175 std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
@@ -190,7 +190,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
190 }; 190 };
191 191
192 // TODO: Remove this when calibration is properly loaded and not calculated 192 // TODO: Remove this when calibration is properly loaded and not calculated
193 if (ring_connected && report_mode == InputReport::STANDARD_FULL_60HZ) { 193 if (ring_connected && report_mode == ReportMode::STANDARD_FULL_60HZ) {
194 InputReportActive data{}; 194 InputReportActive data{};
195 memcpy(&data, buffer.data(), sizeof(InputReportActive)); 195 memcpy(&data, buffer.data(), sizeof(InputReportActive));
196 calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input); 196 calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input);
@@ -228,16 +228,16 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
228 } 228 }
229 229
230 switch (report_mode) { 230 switch (report_mode) {
231 case InputReport::STANDARD_FULL_60HZ: 231 case ReportMode::STANDARD_FULL_60HZ:
232 joycon_poller->ReadActiveMode(buffer, motion_status, ring_status); 232 joycon_poller->ReadActiveMode(buffer, motion_status, ring_status);
233 break; 233 break;
234 case InputReport::NFC_IR_MODE_60HZ: 234 case ReportMode::NFC_IR_MODE_60HZ:
235 joycon_poller->ReadNfcIRMode(buffer, motion_status); 235 joycon_poller->ReadNfcIRMode(buffer, motion_status);
236 break; 236 break;
237 case InputReport::SIMPLE_HID_MODE: 237 case ReportMode::SIMPLE_HID_MODE:
238 joycon_poller->ReadPassiveMode(buffer); 238 joycon_poller->ReadPassiveMode(buffer);
239 break; 239 break;
240 case InputReport::SUBCMD_REPLY: 240 case ReportMode::SUBCMD_REPLY:
241 LOG_DEBUG(Input, "Unhandled command reply"); 241 LOG_DEBUG(Input, "Unhandled command reply");
242 break; 242 break;
243 default: 243 default:
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}
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 188f6ecfa..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,14 +106,14 @@ 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 * @returns output buffer containing the responce 109 * @returns output buffer containing the response
101 */ 110 */
102 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); 111 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
103 112
104 /** 113 /**
105 * Reads the SPI memory stored on the joycon 114 * Reads the SPI memory stored on the joycon
106 * @param Initial address location 115 * @param Initial address location
107 * @returns output object containing the responce 116 * @returns output object containing the response
108 */ 117 */
109 template <typename Output> 118 template <typename Output>
110 requires std::is_trivially_copyable_v<Output> 119 requires std::is_trivially_copyable_v<Output>
@@ -136,19 +145,19 @@ public:
136 /** 145 /**
137 * Waits until there's MCU data available. On timeout returns error 146 * Waits until there's MCU data available. On timeout returns error
138 * @param report mode of the expected reply 147 * @param report mode of the expected reply
139 * @returns a buffer containing the responce 148 * @returns a buffer containing the response
140 */ 149 */
141 DriverResult GetMCUDataResponse(ReportMode report_mode_, std::vector<u8>& output); 150 DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
142 151
143 /** 152 /**
144 * 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
145 * @param report mode of the expected reply 154 * @param report mode of the expected reply
146 * @param sub command to be send 155 * @param sub command to be send
147 * @param buffer data to be send 156 * @param buffer data to be send
148 * @returns output buffer containing the responce 157 * @returns output buffer containing the response
149 */ 158 */
150 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,
151 std::vector<u8>& output); 160 MCUCommandResponse& output);
152 161
153 /** 162 /**
154 * 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 484c208e6..548a4b9e3 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
@@ -32,13 +32,13 @@ DriverResult GenericProtocol::TriggersElapsed() {
32 32
33DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { 33DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
34 ScopedSetBlocking sb(this); 34 ScopedSetBlocking sb(this);
35 std::vector<u8> output; 35 SubCommandResponse output{};
36 36
37 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); 37 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
38 38
39 device_info = {}; 39 device_info = {};
40 if (result == DriverResult::Success) { 40 if (result == DriverResult::Success) {
41 memcpy(&device_info, output.data(), sizeof(DeviceInfo)); 41 device_info = output.device_info;
42 } 42 }
43 43
44 return result; 44 return result;
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) {
132DriverResult IrsProtocol::ConfigureIrs() { 132DriverResult 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() {
226DriverResult IrsProtocol::WriteRegistersStep2() { 227DriverResult 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 14b07bfb5..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 @@
19namespace InputCommon::Joycon { 19namespace InputCommon::Joycon {
20constexpr u32 MaxErrorCount = 50; 20constexpr u32 MaxErrorCount = 50;
21constexpr u32 MaxBufferSize = 368; 21constexpr u32 MaxBufferSize = 368;
22constexpr u32 MaxResponseSize = 49;
23constexpr u32 MaxSubCommandResponseSize = 64;
24constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; 22constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40};
25 23
26using MacAddress = std::array<u8, 6>; 24using MacAddress = std::array<u8, 6>;
27using SerialNumber = std::array<u8, 15>; 25using SerialNumber = std::array<u8, 15>;
28 26
29enum class ControllerType { 27enum 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
38enum class PadAxes { 42enum class PadAxes {
@@ -99,14 +103,6 @@ enum class OutputReport : u8 {
99 USB_CMD = 0x80, 103 USB_CMD = 0x80,
100}; 104};
101 105
102enum 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
110enum class FeatureReport : u8 { 106enum class FeatureReport : u8 {
111 Last_SUBCMD = 0x02, 107 Last_SUBCMD = 0x02,
112 OTA_GW_UPGRADE = 0x70, 108 OTA_GW_UPGRADE = 0x70,
@@ -143,9 +139,10 @@ enum class SubCommand : u8 {
143 ENABLE_VIBRATION = 0x48, 139 ENABLE_VIBRATION = 0x48,
144 GET_REGULATED_VOLTAGE = 0x50, 140 GET_REGULATED_VOLTAGE = 0x50,
145 SET_EXTERNAL_CONFIG = 0x58, 141 SET_EXTERNAL_CONFIG = 0x58,
146 UNKNOWN_RINGCON = 0x59, 142 GET_EXTERNAL_DEVICE_INFO = 0x59,
147 UNKNOWN_RINGCON2 = 0x5A, 143 ENABLE_EXTERNAL_POLLING = 0x5A,
148 UNKNOWN_RINGCON3 = 0x5C, 144 DISABLE_EXTERNAL_POLLING = 0x5B,
145 SET_EXTERNAL_FORMAT_CONFIG = 0x5C,
149}; 146};
150 147
151enum class UsbSubCommand : u8 { 148enum class UsbSubCommand : u8 {
@@ -164,20 +161,26 @@ enum class CalibrationMagic : u8 {
164 USR_MAGIC_1 = 0xA1, 161 USR_MAGIC_1 = 0xA1,
165}; 162};
166 163
167enum class SpiAddress { 164enum 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
183enum class ReportMode : u8 { 186enum 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
194enum class GyroSensitivity : u8 { 199enum class GyroSensitivity : u8 {
@@ -359,10 +364,16 @@ enum class IrRegistersAddress : u16 {
359 DenoiseColor = 0x6901, 364 DenoiseColor = 0x6901,
360}; 365};
361 366
367enum class ExternalDeviceId : u16 {
368 RingController = 0x2000,
369 Starlink = 0x2800,
370};
371
362enum class DriverResult { 372enum 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,
@@ -485,7 +496,7 @@ static_assert(sizeof(MCUConfig) == 0x26, "MCUConfig is an invalid size");
485 496
486#pragma pack(push, 1) 497#pragma pack(push, 1)
487struct InputReportPassive { 498struct InputReportPassive {
488 InputReport report_mode; 499 ReportMode report_mode;
489 u16 button_input; 500 u16 button_input;
490 u8 stick_state; 501 u8 stick_state;
491 std::array<u8, 10> unknown_data; 502 std::array<u8, 10> unknown_data;
@@ -493,7 +504,7 @@ struct InputReportPassive {
493static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size"); 504static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size");
494 505
495struct InputReportActive { 506struct InputReportActive {
496 InputReport report_mode; 507 ReportMode report_mode;
497 u8 packet_id; 508 u8 packet_id;
498 Battery battery_status; 509 Battery battery_status;
499 std::array<u8, 3> button_input; 510 std::array<u8, 3> button_input;
@@ -507,7 +518,7 @@ struct InputReportActive {
507static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size"); 518static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size");
508 519
509struct InputReportNfcIr { 520struct InputReportNfcIr {
510 InputReport report_mode; 521 ReportMode report_mode;
511 u8 packet_id; 522 u8 packet_id;
512 Battery battery_status; 523 Battery battery_status;
513 std::array<u8, 3> button_input; 524 std::array<u8, 3> button_input;
@@ -605,9 +616,11 @@ static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid siz
605 616
606struct DeviceInfo { 617struct DeviceInfo {
607 FirmwareVersion firmware; 618 FirmwareVersion firmware;
619 std::array<u8, 2> unknown_1;
608 MacAddress mac_address; 620 MacAddress mac_address;
621 std::array<u8, 2> unknown_2;
609}; 622};
610static_assert(sizeof(DeviceInfo) == 0x8, "DeviceInfo is an invalid size"); 623static_assert(sizeof(DeviceInfo) == 0xC, "DeviceInfo is an invalid size");
611 624
612struct MotionStatus { 625struct MotionStatus {
613 bool is_enabled; 626 bool is_enabled;
@@ -623,6 +636,53 @@ struct RingStatus {
623 s16 min_value; 636 s16 min_value;
624}; 637};
625 638
639struct VibrationPacket {
640 OutputReport output_report;
641 u8 packet_counter;
642 std::array<u8, 0x8> vibration_data;
643};
644static_assert(sizeof(VibrationPacket) == 0xA, "VibrationPacket is an invalid size");
645
646struct 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};
653static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size");
654
655#pragma pack(push, 1)
656struct ReadSpiPacket {
657 SpiAddress spi_address;
658 INSERT_PADDING_BYTES(0x2);
659 u8 size;
660};
661static_assert(sizeof(ReadSpiPacket) == 0x5, "ReadSpiPacket is an invalid size");
662
663struct 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};
674static_assert(sizeof(SubCommandResponse) == 0x40, "SubCommandResponse is an invalid size");
675#pragma pack(pop)
676
677struct 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};
684static_assert(sizeof(MCUCommandResponse) == 0x170, "MCUCommandResponse is an invalid size");
685
626struct JoyconCallbacks { 686struct JoyconCallbacks {
627 std::function<void(Battery)> on_battery_data; 687 std::function<void(Battery)> on_battery_data;
628 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
111DriverResult NfcProtocol::WaitUntilNfcIsReady() { 111DriverResult 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() {
131DriverResult NfcProtocol::StartPolling(TagFoundData& data) { 132DriverResult 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
154DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { 157DriverResult 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
222DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { 226DriverResult 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
273DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) { 279DriverResult 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
297DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) { 303DriverResult 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
314DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output) { 320DriverResult 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
331DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages) { 337DriverResult 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() {
70DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { 70DriverResult 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
113bool RingConProtocol::IsEnabled() const { 111bool RingConProtocol::IsEnabled() const {