summaryrefslogtreecommitdiff
path: root/src/input_common/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/helpers')
-rw-r--r--src/input_common/helpers/joycon_driver.cpp18
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.cpp210
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.h18
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp157
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h52
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp12
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp13
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h186
-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, 472 insertions, 290 deletions
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/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp
index f6e7e97d5..d8f040f75 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.cpp
+++ b/src/input_common/helpers/joycon_protocol/calibration.cpp
@@ -13,33 +13,33 @@ CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
13 13
14DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { 14DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
15 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
16 std::vector<u8> buffer;
17 DriverResult result{DriverResult::Success}; 16 DriverResult result{DriverResult::Success};
17 JoystickLeftSpiCalibration spi_calibration{};
18 bool has_user_calibration = false;
18 calibration = {}; 19 calibration = {};
19 20
20 result = ReadSPI(CalAddr::USER_LEFT_MAGIC, sizeof(u16), buffer);
21
22 if (result == DriverResult::Success) { 21 if (result == DriverResult::Success) {
23 const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1; 22 result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
24 if (has_user_calibration) {
25 result = ReadSPI(CalAddr::USER_LEFT_DATA, 9, buffer);
26 } else {
27 result = ReadSPI(CalAddr::FACT_LEFT_DATA, 9, buffer);
28 }
29 } 23 }
30 24
31 if (result == DriverResult::Success) { 25 // Read User defined calibration
32 calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]); 26 if (result == DriverResult::Success && has_user_calibration) {
33 calibration.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4)); 27 result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
34 calibration.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
35 calibration.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
36 calibration.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
37 calibration.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
38 } 28 }
39 29
40 // Nintendo fix for drifting stick 30 // Read Factory calibration
41 // result = ReadSPI(0x60, 0x86 ,buffer, 16); 31 if (result == DriverResult::Success && !has_user_calibration) {
42 // calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]); 32 result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
33 }
34
35 if (result == DriverResult::Success) {
36 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
37 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
38 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
39 calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
40 calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
41 calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
42 }
43 43
44 // Set a valid default calibration if data is missing 44 // Set a valid default calibration if data is missing
45 ValidateCalibration(calibration); 45 ValidateCalibration(calibration);
@@ -49,33 +49,33 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
49 49
50DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { 50DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
51 ScopedSetBlocking sb(this); 51 ScopedSetBlocking sb(this);
52 std::vector<u8> buffer;
53 DriverResult result{DriverResult::Success}; 52 DriverResult result{DriverResult::Success};
53 JoystickRightSpiCalibration spi_calibration{};
54 bool has_user_calibration = false;
54 calibration = {}; 55 calibration = {};
55 56
56 result = ReadSPI(CalAddr::USER_RIGHT_MAGIC, sizeof(u16), buffer);
57
58 if (result == DriverResult::Success) { 57 if (result == DriverResult::Success) {
59 const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1; 58 result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
60 if (has_user_calibration) {
61 result = ReadSPI(CalAddr::USER_RIGHT_DATA, 9, buffer);
62 } else {
63 result = ReadSPI(CalAddr::FACT_RIGHT_DATA, 9, buffer);
64 }
65 } 59 }
66 60
67 if (result == DriverResult::Success) { 61 // Read User defined calibration
68 calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]); 62 if (result == DriverResult::Success && has_user_calibration) {
69 calibration.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4)); 63 result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
70 calibration.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]); 64 }
71 calibration.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4)); 65
72 calibration.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]); 66 // Read Factory calibration
73 calibration.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4)); 67 if (result == DriverResult::Success && !has_user_calibration) {
68 result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
74 } 69 }
75 70
76 // Nintendo fix for drifting stick 71 if (result == DriverResult::Success) {
77 // buffer = ReadSPI(0x60, 0x98 , 16); 72 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
78 // joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]); 73 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
74 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
75 calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
76 calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
77 calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
78 }
79 79
80 // Set a valid default calibration if data is missing 80 // Set a valid default calibration if data is missing
81 ValidateCalibration(calibration); 81 ValidateCalibration(calibration);
@@ -85,39 +85,41 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
85 85
86DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { 86DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
87 ScopedSetBlocking sb(this); 87 ScopedSetBlocking sb(this);
88 std::vector<u8> buffer;
89 DriverResult result{DriverResult::Success}; 88 DriverResult result{DriverResult::Success};
89 ImuSpiCalibration spi_calibration{};
90 bool has_user_calibration = false;
90 calibration = {}; 91 calibration = {};
91 92
92 result = ReadSPI(CalAddr::USER_IMU_MAGIC, sizeof(u16), buffer);
93
94 if (result == DriverResult::Success) { 93 if (result == DriverResult::Success) {
95 const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1; 94 result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
96 if (has_user_calibration) { 95 }
97 result = ReadSPI(CalAddr::USER_IMU_DATA, sizeof(IMUCalibration), buffer); 96
98 } else { 97 // Read User defined calibration
99 result = ReadSPI(CalAddr::FACT_IMU_DATA, sizeof(IMUCalibration), buffer); 98 if (result == DriverResult::Success && has_user_calibration) {
100 } 99 result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
100 }
101
102 // Read Factory calibration
103 if (result == DriverResult::Success && !has_user_calibration) {
104 result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
101 } 105 }
102 106
103 if (result == DriverResult::Success) { 107 if (result == DriverResult::Success) {
104 IMUCalibration device_calibration{}; 108 calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
105 memcpy(&device_calibration, buffer.data(), sizeof(IMUCalibration)); 109 calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
106 calibration.accelerometer[0].offset = device_calibration.accelerometer_offset[0]; 110 calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
107 calibration.accelerometer[1].offset = device_calibration.accelerometer_offset[1];
108 calibration.accelerometer[2].offset = device_calibration.accelerometer_offset[2];
109 111
110 calibration.accelerometer[0].scale = device_calibration.accelerometer_scale[0]; 112 calibration.accelerometer[0].scale = spi_calibration.accelerometer_scale[0];
111 calibration.accelerometer[1].scale = device_calibration.accelerometer_scale[1]; 113 calibration.accelerometer[1].scale = spi_calibration.accelerometer_scale[1];
112 calibration.accelerometer[2].scale = device_calibration.accelerometer_scale[2]; 114 calibration.accelerometer[2].scale = spi_calibration.accelerometer_scale[2];
113 115
114 calibration.gyro[0].offset = device_calibration.gyroscope_offset[0]; 116 calibration.gyro[0].offset = spi_calibration.gyroscope_offset[0];
115 calibration.gyro[1].offset = device_calibration.gyroscope_offset[1]; 117 calibration.gyro[1].offset = spi_calibration.gyroscope_offset[1];
116 calibration.gyro[2].offset = device_calibration.gyroscope_offset[2]; 118 calibration.gyro[2].offset = spi_calibration.gyroscope_offset[2];
117 119
118 calibration.gyro[0].scale = device_calibration.gyroscope_scale[0]; 120 calibration.gyro[0].scale = spi_calibration.gyroscope_scale[0];
119 calibration.gyro[1].scale = device_calibration.gyroscope_scale[1]; 121 calibration.gyro[1].scale = spi_calibration.gyroscope_scale[1];
120 calibration.gyro[2].scale = device_calibration.gyroscope_scale[2]; 122 calibration.gyro[2].scale = spi_calibration.gyroscope_scale[2];
121 } 123 }
122 124
123 ValidateCalibration(calibration); 125 ValidateCalibration(calibration);
@@ -127,10 +129,12 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
127 129
128DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, 130DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
129 s16 current_value) { 131 s16 current_value) {
132 constexpr s16 DefaultRingRange{800};
133
130 // TODO: Get default calibration form ring itself 134 // TODO: Get default calibration form ring itself
131 if (ring_data_max == 0 && ring_data_min == 0) { 135 if (ring_data_max == 0 && ring_data_min == 0) {
132 ring_data_max = current_value + 800; 136 ring_data_max = current_value + DefaultRingRange;
133 ring_data_min = current_value - 800; 137 ring_data_min = current_value - DefaultRingRange;
134 ring_data_default = current_value; 138 ring_data_default = current_value;
135 } 139 }
136 ring_data_max = std::max(ring_data_max, current_value); 140 ring_data_max = std::max(ring_data_max, current_value);
@@ -143,42 +147,72 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
143 return DriverResult::Success; 147 return DriverResult::Success;
144} 148}
145 149
150DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
151 bool& has_user_calibration) {
152 MagicSpiCalibration spi_magic{};
153 const DriverResult result{ReadSPI(address, spi_magic)};
154 has_user_calibration = false;
155 if (result == DriverResult::Success) {
156 has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
157 spi_magic.second == CalibrationMagic::USR_MAGIC_1;
158 }
159 return result;
160}
161
162u16 CalibrationProtocol::GetXAxisCalibrationValue(std::span<u8> block) const {
163 return static_cast<u16>(((block[1] & 0x0F) << 8) | block[0]);
164}
165
166u16 CalibrationProtocol::GetYAxisCalibrationValue(std::span<u8> block) const {
167 return static_cast<u16>((block[2] << 4) | (block[1] >> 4));
168}
169
146void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) { 170void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) {
147 constexpr u16 DefaultStickCenter{2048}; 171 constexpr u16 DefaultStickCenter{0x800};
148 constexpr u16 DefaultStickRange{1740}; 172 constexpr u16 DefaultStickRange{0x6cc};
149 173
150 if (calibration.x.center == 0xFFF || calibration.x.center == 0) { 174 calibration.x.center = ValidateValue(calibration.x.center, DefaultStickCenter);
151 calibration.x.center = DefaultStickCenter; 175 calibration.x.max = ValidateValue(calibration.x.max, DefaultStickRange);
152 } 176 calibration.x.min = ValidateValue(calibration.x.min, DefaultStickRange);
153 if (calibration.x.max == 0xFFF || calibration.x.max == 0) { 177
154 calibration.x.max = DefaultStickRange; 178 calibration.y.center = ValidateValue(calibration.y.center, DefaultStickCenter);
179 calibration.y.max = ValidateValue(calibration.y.max, DefaultStickRange);
180 calibration.y.min = ValidateValue(calibration.y.min, DefaultStickRange);
181}
182
183void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) {
184 constexpr s16 DefaultAccelerometerScale{0x4000};
185 constexpr s16 DefaultGyroScale{0x3be7};
186 constexpr s16 DefaultOffset{0};
187
188 for (auto& sensor : calibration.accelerometer) {
189 sensor.scale = ValidateValue(sensor.scale, DefaultAccelerometerScale);
190 sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
155 } 191 }
156 if (calibration.x.min == 0xFFF || calibration.x.min == 0) { 192 for (auto& sensor : calibration.gyro) {
157 calibration.x.min = DefaultStickRange; 193 sensor.scale = ValidateValue(sensor.scale, DefaultGyroScale);
194 sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
158 } 195 }
196}
159 197
160 if (calibration.y.center == 0xFFF || calibration.y.center == 0) { 198u16 CalibrationProtocol::ValidateValue(u16 value, u16 default_value) const {
161 calibration.y.center = DefaultStickCenter; 199 if (value == 0) {
162 } 200 return default_value;
163 if (calibration.y.max == 0xFFF || calibration.y.max == 0) {
164 calibration.y.max = DefaultStickRange;
165 } 201 }
166 if (calibration.y.min == 0xFFF || calibration.y.min == 0) { 202 if (value == 0xFFF) {
167 calibration.y.min = DefaultStickRange; 203 return default_value;
168 } 204 }
205 return value;
169} 206}
170 207
171void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) { 208s16 CalibrationProtocol::ValidateValue(s16 value, s16 default_value) const {
172 for (auto& sensor : calibration.accelerometer) { 209 if (value == 0) {
173 if (sensor.scale == 0) { 210 return default_value;
174 sensor.scale = 0x4000;
175 }
176 } 211 }
177 for (auto& sensor : calibration.gyro) { 212 if (value == 0xFFF) {
178 if (sensor.scale == 0) { 213 return default_value;
179 sensor.scale = 0x3be7;
180 }
181 } 214 }
215 return value;
182} 216}
183 217
184} // namespace InputCommon::Joycon 218} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h
index afb52a36a..c6fd0f729 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.h
+++ b/src/input_common/helpers/joycon_protocol/calibration.h
@@ -53,9 +53,27 @@ public:
53 DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); 53 DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
54 54
55private: 55private:
56 /// Returns true if the specified address corresponds to the magic value of user calibration
57 DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
58
59 /// Converts a raw calibration block to an u16 value containing the x axis value
60 u16 GetXAxisCalibrationValue(std::span<u8> block) const;
61
62 /// Converts a raw calibration block to an u16 value containing the y axis value
63 u16 GetYAxisCalibrationValue(std::span<u8> block) const;
64
65 /// Ensures that all joystick calibration values are set
56 void ValidateCalibration(JoyStickCalibration& calibration); 66 void ValidateCalibration(JoyStickCalibration& calibration);
67
68 /// Ensures that all motion calibration values are set
57 void ValidateCalibration(MotionCalibration& calibration); 69 void ValidateCalibration(MotionCalibration& calibration);
58 70
71 /// Returns the default value if the value is either zero or 0xFFF
72 u16 ValidateValue(u16 value, u16 default_value) const;
73
74 /// Returns the default value if the value is either zero or 0xFFF
75 s16 ValidateValue(s16 value, s16 default_value) const;
76
59 s16 ring_data_max = 0; 77 s16 ring_data_max = 0;
60 s16 ring_data_default = 0; 78 s16 ring_data_default = 0;
61 s16 ring_data_min = 0; 79 s16 ring_data_min = 0;
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 417d0dcc5..2b42a4555 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -22,12 +22,9 @@ void JoyconCommonProtocol::SetNonBlocking() {
22} 22}
23 23
24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { 24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
25 std::vector<u8> buffer; 25 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
26 const auto result = ReadSPI(CalAddr::DEVICE_TYPE, 1, buffer);
27 controller_type = ControllerType::None;
28 26
29 if (result == DriverResult::Success) { 27 if (result == DriverResult::Success) {
30 controller_type = static_cast<ControllerType>(buffer[0]);
31 // Fallback to 3rd party pro controllers 28 // Fallback to 3rd party pro controllers
32 if (controller_type == ControllerType::None) { 29 if (controller_type == ControllerType::None) {
33 controller_type = ControllerType::Pro; 30 controller_type = ControllerType::Pro;
@@ -40,6 +37,7 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
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,44 +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::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) { 159DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
160 constexpr std::size_t HeaderSize = 5;
152 constexpr std::size_t MaxTries = 10; 161 constexpr std::size_t MaxTries = 10;
153 std::size_t tries = 0; 162 std::size_t tries = 0;
154 std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, size}; 163 SubCommandResponse response{};
155 std::vector<u8> local_buffer(size + 20); 164 std::array<u8, sizeof(ReadSpiPacket)> buffer{};
156 165 const ReadSpiPacket packet_data{
157 buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); 166 .spi_address = addr,
158 buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8); 167 .size = static_cast<u8>(output.size()),
168 };
169
170 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
159 do { 171 do {
160 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, local_buffer); 172 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
161 if (result != DriverResult::Success) { 173 if (result != DriverResult::Success) {
162 return result; 174 return result;
163 } 175 }
@@ -165,10 +177,14 @@ DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8
165 if (tries++ > MaxTries) { 177 if (tries++ > MaxTries) {
166 return DriverResult::Timeout; 178 return DriverResult::Timeout;
167 } 179 }
168 } while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]); 180 } while (response.spi_address != addr);
181
182 if (response.command_data.size() < packet_data.size + HeaderSize) {
183 return DriverResult::WrongReply;
184 }
169 185
170 // Remove header from output 186 // Remove header from output
171 output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.begin() + 20 + size); 187 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
172 return DriverResult::Success; 188 return DriverResult::Success;
173} 189}
174 190
@@ -177,7 +193,7 @@ DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
177 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); 193 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
178 194
179 if (result != DriverResult::Success) { 195 if (result != DriverResult::Success) {
180 LOG_ERROR(Input, "SendMCUData failed with error {}", result); 196 LOG_ERROR(Input, "Failed with error {}", result);
181 } 197 }
182 198
183 return result; 199 return result;
@@ -192,22 +208,21 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
192 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); 208 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
193 209
194 if (result != DriverResult::Success) { 210 if (result != DriverResult::Success) {
195 LOG_ERROR(Input, "Set MCU config failed with error {}", result); 211 LOG_ERROR(Input, "Failed with error {}", result);
196 } 212 }
197 213
198 return result; 214 return result;
199} 215}
200 216
201DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, 217DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
202 std::vector<u8>& output) { 218 MCUCommandResponse& output) {
203 const int report_mode = static_cast<u8>(report_mode_);
204 constexpr int TimeoutMili = 200; 219 constexpr int TimeoutMili = 200;
205 constexpr int MaxTries = 9; 220 constexpr int MaxTries = 9;
206 int tries = 0; 221 int tries = 0;
207 output.resize(0x170);
208 222
209 do { 223 do {
210 int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), 0x170, TimeoutMili); 224 int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output),
225 sizeof(MCUCommandResponse), TimeoutMili);
211 226
212 if (result < 1) { 227 if (result < 1) {
213 LOG_ERROR(Input, "No response from joycon attempt {}", tries); 228 LOG_ERROR(Input, "No response from joycon attempt {}", tries);
@@ -215,28 +230,29 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_,
215 if (tries++ > MaxTries) { 230 if (tries++ > MaxTries) {
216 return DriverResult::Timeout; 231 return DriverResult::Timeout;
217 } 232 }
218 } while (output[0] != report_mode || output[49] == 0xFF); 233 } while (output.input_report.report_mode != report_mode ||
219 234 output.mcu_report == MCUReport::EmptyAwaitingCmd);
220 if (output[0] != report_mode || output[49] == 0xFF) {
221 return DriverResult::WrongReply;
222 }
223 235
224 return DriverResult::Success; 236 return DriverResult::Success;
225} 237}
226 238
227DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, 239DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc,
228 std::span<const u8> buffer, 240 std::span<const u8> buffer,
229 std::vector<u8>& output) { 241 MCUCommandResponse& output) {
230 std::vector<u8> local_buffer(MaxResponseSize); 242 SubCommandPacket packet{
231 243 .output_report = OutputReport::MCU_DATA,
232 local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); 244 .packet_counter = GetCounter(),
233 local_buffer[1] = GetCounter(); 245 .sub_command = sc,
234 local_buffer[9] = static_cast<u8>(sc); 246 .command_data = {},
235 for (std::size_t i = 0; i < buffer.size(); ++i) { 247 };
236 local_buffer[10 + i] = buffer[i]; 248
249 if (buffer.size() > packet.command_data.size()) {
250 return DriverResult::InvalidParameters;
237 } 251 }
238 252
239 auto result = SendData(local_buffer); 253 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
254
255 auto result = SendData(packet);
240 256
241 if (result != DriverResult::Success) { 257 if (result != DriverResult::Success) {
242 return result; 258 return result;
@@ -248,7 +264,7 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubComman
248} 264}
249 265
250DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { 266DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) {
251 std::vector<u8> output; 267 MCUCommandResponse output{};
252 constexpr std::size_t MaxTries{8}; 268 constexpr std::size_t MaxTries{8};
253 std::size_t tries{}; 269 std::size_t tries{};
254 270
@@ -263,7 +279,8 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
263 if (tries++ > MaxTries) { 279 if (tries++ > MaxTries) {
264 return DriverResult::WrongReply; 280 return DriverResult::WrongReply;
265 } 281 }
266 } while (output[49] != 1 || output[56] != static_cast<u8>(mode)); 282 } while (output.mcu_report != MCUReport::StateReport ||
283 output.mcu_data[6] != static_cast<u8>(mode));
267 284
268 return DriverResult::Success; 285 return DriverResult::Success;
269} 286}
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 903bcf402..f44f73ba4 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -57,22 +57,31 @@ public:
57 * Sends data to the joycon device 57 * Sends data to the joycon device
58 * @param buffer data to be send 58 * @param buffer data to be send
59 */ 59 */
60 DriverResult SendData(std::span<const u8> buffer); 60 DriverResult SendRawData(std::span<const u8> buffer);
61
62 template <typename Output>
63 requires std::is_trivially_copyable_v<Output>
64 DriverResult SendData(const Output& output) {
65 std::array<u8, sizeof(Output)> buffer;
66 std::memcpy(buffer.data(), &output, sizeof(Output));
67 return SendRawData(buffer);
68 }
61 69
62 /** 70 /**
63 * Waits for incoming data of the joycon device that matchs the subcommand 71 * Waits for incoming data of the joycon device that matchs the subcommand
64 * @param sub_command type of data to be returned 72 * @param sub_command type of data to be returned
65 * @returns a buffer containing the responce 73 * @returns a buffer containing the response
66 */ 74 */
67 DriverResult GetSubCommandResponse(SubCommand sub_command, std::vector<u8>& output); 75 DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output);
68 76
69 /** 77 /**
70 * Sends a sub command to the device and waits for it's reply 78 * Sends a sub command to the device and waits for it's reply
71 * @param sc sub command to be send 79 * @param sc sub command to be send
72 * @param buffer data to be send 80 * @param buffer data to be send
73 * @returns output buffer containing the responce 81 * @returns output buffer containing the response
74 */ 82 */
75 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output); 83 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
84 SubCommandResponse& output);
76 85
77 /** 86 /**
78 * Sends a sub command to the device and waits for it's reply and ignores the output 87 * Sends a sub command to the device and waits for it's reply and ignores the output
@@ -97,10 +106,29 @@ public:
97 /** 106 /**
98 * Reads the SPI memory stored on the joycon 107 * Reads the SPI memory stored on the joycon
99 * @param Initial address location 108 * @param Initial address location
100 * @param size in bytes to be read 109 * @returns output buffer containing the response
101 * @returns output buffer containing the responce
102 */ 110 */
103 DriverResult ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output); 111 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
112
113 /**
114 * Reads the SPI memory stored on the joycon
115 * @param Initial address location
116 * @returns output object containing the response
117 */
118 template <typename Output>
119 requires std::is_trivially_copyable_v<Output>
120 DriverResult ReadSPI(SpiAddress addr, Output& output) {
121 std::array<u8, sizeof(Output)> buffer;
122 output = {};
123
124 const auto result = ReadRawSPI(addr, buffer);
125 if (result != DriverResult::Success) {
126 return result;
127 }
128
129 std::memcpy(&output, buffer.data(), sizeof(Output));
130 return DriverResult::Success;
131 }
104 132
105 /** 133 /**
106 * Enables MCU chip on the joycon 134 * Enables MCU chip on the joycon
@@ -117,19 +145,19 @@ public:
117 /** 145 /**
118 * Waits until there's MCU data available. On timeout returns error 146 * Waits until there's MCU data available. On timeout returns error
119 * @param report mode of the expected reply 147 * @param report mode of the expected reply
120 * @returns a buffer containing the responce 148 * @returns a buffer containing the response
121 */ 149 */
122 DriverResult GetMCUDataResponse(ReportMode report_mode_, std::vector<u8>& output); 150 DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
123 151
124 /** 152 /**
125 * Sends data to the MCU chip and waits for it's reply 153 * Sends data to the MCU chip and waits for it's reply
126 * @param report mode of the expected reply 154 * @param report mode of the expected reply
127 * @param sub command to be send 155 * @param sub command to be send
128 * @param buffer data to be send 156 * @param buffer data to be send
129 * @returns output buffer containing the responce 157 * @returns output buffer containing the response
130 */ 158 */
131 DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer, 159 DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer,
132 std::vector<u8>& output); 160 MCUCommandResponse& output);
133 161
134 /** 162 /**
135 * Wait's until the MCU chip is on the specified mode 163 * Wait's until the MCU chip is on the specified mode
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
index 63cfb1369..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;
@@ -71,8 +71,8 @@ DriverResult GenericProtocol::GetBattery(u32& battery_level) {
71 71
72DriverResult GenericProtocol::GetColor(Color& color) { 72DriverResult GenericProtocol::GetColor(Color& color) {
73 ScopedSetBlocking sb(this); 73 ScopedSetBlocking sb(this);
74 std::vector<u8> buffer; 74 std::array<u8, 12> buffer{};
75 const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer); 75 const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
76 76
77 color = {}; 77 color = {};
78 if (result == DriverResult::Success) { 78 if (result == DriverResult::Success) {
@@ -87,8 +87,8 @@ DriverResult GenericProtocol::GetColor(Color& color) {
87 87
88DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { 88DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
89 ScopedSetBlocking sb(this); 89 ScopedSetBlocking sb(this);
90 std::vector<u8> buffer; 90 std::array<u8, 16> buffer{};
91 const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer); 91 const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
92 92
93 serial_number = {}; 93 serial_number = {};
94 if (result == DriverResult::Success) { 94 if (result == DriverResult::Success) {
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 182d2c15b..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 {
@@ -159,26 +156,31 @@ enum class UsbSubCommand : u8 {
159 SEND_UART = 0x92, 156 SEND_UART = 0x92,
160}; 157};
161 158
162enum class CalMagic : u8 { 159enum class CalibrationMagic : u8 {
163 USR_MAGIC_0 = 0xB2, 160 USR_MAGIC_0 = 0xB2,
164 USR_MAGIC_1 = 0xA1, 161 USR_MAGIC_1 = 0xA1,
165 USRR_MAGI_SIZE = 2,
166}; 162};
167 163
168enum class CalAddr { 164enum class SpiAddress : u16 {
169 SERIAL_NUMBER = 0X6000, 165 MAGIC = 0x0000,
170 DEVICE_TYPE = 0X6012, 166 MAC_ADDRESS = 0x0015,
171 COLOR_EXIST = 0X601B, 167 PAIRING_INFO = 0x2000,
172 FACT_LEFT_DATA = 0X603d, 168 SHIPMENT = 0x5000,
173 FACT_RIGHT_DATA = 0X6046, 169 SERIAL_NUMBER = 0x6000,
174 COLOR_DATA = 0X6050, 170 DEVICE_TYPE = 0x6012,
175 FACT_IMU_DATA = 0X6020, 171 FORMAT_VERSION = 0x601B,
176 USER_LEFT_MAGIC = 0X8010, 172 FACT_IMU_DATA = 0x6020,
177 USER_LEFT_DATA = 0X8012, 173 FACT_LEFT_DATA = 0x603d,
178 USER_RIGHT_MAGIC = 0X801B, 174 FACT_RIGHT_DATA = 0x6046,
179 USER_RIGHT_DATA = 0X801D, 175 COLOR_DATA = 0x6050,
180 USER_IMU_MAGIC = 0X8026, 176 DESIGN_VARIATION = 0x605C,
181 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,
182}; 184};
183 185
184enum class ReportMode : u8 { 186enum class ReportMode : u8 {
@@ -186,10 +188,12 @@ enum class ReportMode : u8 {
186 ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01, 188 ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01,
187 ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02, 189 ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02,
188 ACTIVE_POLLING_IR_CAMERA_DATA = 0x03, 190 ACTIVE_POLLING_IR_CAMERA_DATA = 0x03,
191 SUBCMD_REPLY = 0x21,
189 MCU_UPDATE_STATE = 0x23, 192 MCU_UPDATE_STATE = 0x23,
190 STANDARD_FULL_60HZ = 0x30, 193 STANDARD_FULL_60HZ = 0x30,
191 NFC_IR_MODE_60HZ = 0x31, 194 NFC_IR_MODE_60HZ = 0x31,
192 SIMPLE_HID_MODE = 0x3F, 195 SIMPLE_HID_MODE = 0x3F,
196 INPUT_USB_RESPONSE = 0x81,
193}; 197};
194 198
195enum class GyroSensitivity : u8 { 199enum class GyroSensitivity : u8 {
@@ -360,10 +364,16 @@ enum class IrRegistersAddress : u16 {
360 DenoiseColor = 0x6901, 364 DenoiseColor = 0x6901,
361}; 365};
362 366
367enum class ExternalDeviceId : u16 {
368 RingController = 0x2000,
369 Starlink = 0x2800,
370};
371
363enum class DriverResult { 372enum class DriverResult {
364 Success, 373 Success,
365 WrongReply, 374 WrongReply,
366 Timeout, 375 Timeout,
376 InvalidParameters,
367 UnsupportedControllerType, 377 UnsupportedControllerType,
368 HandleInUse, 378 HandleInUse,
369 ErrorReadingData, 379 ErrorReadingData,
@@ -396,10 +406,35 @@ struct MotionData {
396 u64 delta_timestamp{}; 406 u64 delta_timestamp{};
397}; 407};
398 408
409// Output from SPI read command containing user calibration magic
410struct MagicSpiCalibration {
411 CalibrationMagic first;
412 CalibrationMagic second;
413};
414static_assert(sizeof(MagicSpiCalibration) == 0x2, "MagicSpiCalibration is an invalid size");
415
416// Output from SPI read command containing left joystick calibration
417struct JoystickLeftSpiCalibration {
418 std::array<u8, 3> max;
419 std::array<u8, 3> center;
420 std::array<u8, 3> min;
421};
422static_assert(sizeof(JoystickLeftSpiCalibration) == 0x9,
423 "JoystickLeftSpiCalibration is an invalid size");
424
425// Output from SPI read command containing right joystick calibration
426struct JoystickRightSpiCalibration {
427 std::array<u8, 3> center;
428 std::array<u8, 3> min;
429 std::array<u8, 3> max;
430};
431static_assert(sizeof(JoystickRightSpiCalibration) == 0x9,
432 "JoystickRightSpiCalibration is an invalid size");
433
399struct JoyStickAxisCalibration { 434struct JoyStickAxisCalibration {
400 u16 max{1}; 435 u16 max;
401 u16 min{1}; 436 u16 min;
402 u16 center{0}; 437 u16 center;
403}; 438};
404 439
405struct JoyStickCalibration { 440struct JoyStickCalibration {
@@ -407,6 +442,14 @@ struct JoyStickCalibration {
407 JoyStickAxisCalibration y; 442 JoyStickAxisCalibration y;
408}; 443};
409 444
445struct ImuSpiCalibration {
446 std::array<s16, 3> accelerometer_offset;
447 std::array<s16, 3> accelerometer_scale;
448 std::array<s16, 3> gyroscope_offset;
449 std::array<s16, 3> gyroscope_scale;
450};
451static_assert(sizeof(ImuSpiCalibration) == 0x18, "ImuSpiCalibration is an invalid size");
452
410struct RingCalibration { 453struct RingCalibration {
411 s16 default_value; 454 s16 default_value;
412 s16 max_value; 455 s16 max_value;
@@ -453,7 +496,7 @@ static_assert(sizeof(MCUConfig) == 0x26, "MCUConfig is an invalid size");
453 496
454#pragma pack(push, 1) 497#pragma pack(push, 1)
455struct InputReportPassive { 498struct InputReportPassive {
456 InputReport report_mode; 499 ReportMode report_mode;
457 u16 button_input; 500 u16 button_input;
458 u8 stick_state; 501 u8 stick_state;
459 std::array<u8, 10> unknown_data; 502 std::array<u8, 10> unknown_data;
@@ -461,7 +504,7 @@ struct InputReportPassive {
461static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size"); 504static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size");
462 505
463struct InputReportActive { 506struct InputReportActive {
464 InputReport report_mode; 507 ReportMode report_mode;
465 u8 packet_id; 508 u8 packet_id;
466 Battery battery_status; 509 Battery battery_status;
467 std::array<u8, 3> button_input; 510 std::array<u8, 3> button_input;
@@ -475,7 +518,7 @@ struct InputReportActive {
475static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size"); 518static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size");
476 519
477struct InputReportNfcIr { 520struct InputReportNfcIr {
478 InputReport report_mode; 521 ReportMode report_mode;
479 u8 packet_id; 522 u8 packet_id;
480 Battery battery_status; 523 Battery battery_status;
481 std::array<u8, 3> button_input; 524 std::array<u8, 3> button_input;
@@ -488,14 +531,6 @@ struct InputReportNfcIr {
488static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size"); 531static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size");
489#pragma pack(pop) 532#pragma pack(pop)
490 533
491struct IMUCalibration {
492 std::array<s16, 3> accelerometer_offset;
493 std::array<s16, 3> accelerometer_scale;
494 std::array<s16, 3> gyroscope_offset;
495 std::array<s16, 3> gyroscope_scale;
496};
497static_assert(sizeof(IMUCalibration) == 0x18, "IMUCalibration is an invalid size");
498
499struct NFCReadBlock { 534struct NFCReadBlock {
500 u8 start; 535 u8 start;
501 u8 end; 536 u8 end;
@@ -581,9 +616,11 @@ static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid siz
581 616
582struct DeviceInfo { 617struct DeviceInfo {
583 FirmwareVersion firmware; 618 FirmwareVersion firmware;
619 std::array<u8, 2> unknown_1;
584 MacAddress mac_address; 620 MacAddress mac_address;
621 std::array<u8, 2> unknown_2;
585}; 622};
586static_assert(sizeof(DeviceInfo) == 0x8, "DeviceInfo is an invalid size"); 623static_assert(sizeof(DeviceInfo) == 0xC, "DeviceInfo is an invalid size");
587 624
588struct MotionStatus { 625struct MotionStatus {
589 bool is_enabled; 626 bool is_enabled;
@@ -599,6 +636,53 @@ struct RingStatus {
599 s16 min_value; 636 s16 min_value;
600}; 637};
601 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
602struct JoyconCallbacks { 686struct JoyconCallbacks {
603 std::function<void(Battery)> on_battery_data; 687 std::function<void(Battery)> on_battery_data;
604 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 {