diff options
Diffstat (limited to 'src/input_common/helpers/joycon_protocol/rumble.cpp')
| -rw-r--r-- | src/input_common/helpers/joycon_protocol/rumble.cpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp new file mode 100644 index 000000000..17ee38863 --- /dev/null +++ b/src/input_common/helpers/joycon_protocol/rumble.cpp | |||
| @@ -0,0 +1,299 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "input_common/helpers/joycon_protocol/rumble.h" | ||
| 6 | |||
| 7 | namespace InputCommon::Joycon { | ||
| 8 | |||
| 9 | RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) | ||
| 10 | : JoyconCommonProtocol(handle) {} | ||
| 11 | |||
| 12 | DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { | ||
| 13 | LOG_DEBUG(Input, "Enable Rumble"); | ||
| 14 | const std::vector<u8> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; | ||
| 15 | std::vector<u8> output; | ||
| 16 | SetBlocking(); | ||
| 17 | const auto result = SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer, output); | ||
| 18 | SetNonBlocking(); | ||
| 19 | return result; | ||
| 20 | } | ||
| 21 | |||
| 22 | DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { | ||
| 23 | std::vector<u8> buffer(sizeof(DefaultVibrationBuffer)); | ||
| 24 | |||
| 25 | if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { | ||
| 26 | return SendVibrationReport(DefaultVibrationBuffer); | ||
| 27 | } | ||
| 28 | |||
| 29 | // Protect joycons from damage from strong vibrations | ||
| 30 | const f32 clamp_amplitude = | ||
| 31 | 1.0f / std::max(1.0f, vibration.high_amplitude + vibration.low_amplitude); | ||
| 32 | |||
| 33 | const u16 encoded_high_frequency = EncodeHighFrequency(vibration.high_frequency); | ||
| 34 | const u8 encoded_high_amplitude = | ||
| 35 | EncodeHighAmplitude(vibration.high_amplitude * clamp_amplitude); | ||
| 36 | const u8 encoded_low_frequency = EncodeLowFrequency(vibration.low_frequency); | ||
| 37 | const u16 encoded_low_amplitude = EncodeLowAmplitude(vibration.low_amplitude * clamp_amplitude); | ||
| 38 | |||
| 39 | buffer[0] = static_cast<u8>(encoded_high_frequency & 0xFF); | ||
| 40 | buffer[1] = static_cast<u8>(encoded_high_amplitude | ((encoded_high_frequency >> 8) & 0x01)); | ||
| 41 | buffer[2] = static_cast<u8>(encoded_low_frequency | ((encoded_low_amplitude >> 8) & 0x80)); | ||
| 42 | buffer[3] = static_cast<u8>(encoded_low_amplitude & 0xFF); | ||
| 43 | |||
| 44 | // Duplicate rumble for now | ||
| 45 | buffer[4] = buffer[0]; | ||
| 46 | buffer[5] = buffer[1]; | ||
| 47 | buffer[6] = buffer[2]; | ||
| 48 | buffer[7] = buffer[3]; | ||
| 49 | |||
| 50 | return SendVibrationReport(buffer); | ||
| 51 | } | ||
| 52 | |||
| 53 | u16 RumbleProtocol::EncodeHighFrequency(f32 frequency) const { | ||
| 54 | const u8 new_frequency = | ||
| 55 | static_cast<u8>(std::clamp(std::log2(frequency / 10.0f) * 32.0f, 0.0f, 255.0f)); | ||
| 56 | return static_cast<u16>((new_frequency - 0x60) * 4); | ||
| 57 | } | ||
| 58 | |||
| 59 | u8 RumbleProtocol::EncodeLowFrequency(f32 frequency) const { | ||
| 60 | const u8 new_frequency = | ||
| 61 | static_cast<u8>(std::clamp(std::log2(frequency / 10.0f) * 32.0f, 0.0f, 255.0f)); | ||
| 62 | return static_cast<u8>(new_frequency - 0x40); | ||
| 63 | } | ||
| 64 | |||
| 65 | u8 RumbleProtocol::EncodeHighAmplitude(f32 amplitude) const { | ||
| 66 | /* More information about these values can be found here: | ||
| 67 | * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md | ||
| 68 | */ | ||
| 69 | constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ | ||
| 70 | std::pair<f32, int>{0.0f, 0x0}, | ||
| 71 | {0.01f, 0x2}, | ||
| 72 | {0.012f, 0x4}, | ||
| 73 | {0.014f, 0x6}, | ||
| 74 | {0.017f, 0x8}, | ||
| 75 | {0.02f, 0x0a}, | ||
| 76 | {0.024f, 0x0c}, | ||
| 77 | {0.028f, 0x0e}, | ||
| 78 | {0.033f, 0x10}, | ||
| 79 | {0.04f, 0x12}, | ||
| 80 | {0.047f, 0x14}, | ||
| 81 | {0.056f, 0x16}, | ||
| 82 | {0.067f, 0x18}, | ||
| 83 | {0.08f, 0x1a}, | ||
| 84 | {0.095f, 0x1c}, | ||
| 85 | {0.112f, 0x1e}, | ||
| 86 | {0.117f, 0x20}, | ||
| 87 | {0.123f, 0x22}, | ||
| 88 | {0.128f, 0x24}, | ||
| 89 | {0.134f, 0x26}, | ||
| 90 | {0.14f, 0x28}, | ||
| 91 | {0.146f, 0x2a}, | ||
| 92 | {0.152f, 0x2c}, | ||
| 93 | {0.159f, 0x2e}, | ||
| 94 | {0.166f, 0x30}, | ||
| 95 | {0.173f, 0x32}, | ||
| 96 | {0.181f, 0x34}, | ||
| 97 | {0.189f, 0x36}, | ||
| 98 | {0.198f, 0x38}, | ||
| 99 | {0.206f, 0x3a}, | ||
| 100 | {0.215f, 0x3c}, | ||
| 101 | {0.225f, 0x3e}, | ||
| 102 | {0.23f, 0x40}, | ||
| 103 | {0.235f, 0x42}, | ||
| 104 | {0.24f, 0x44}, | ||
| 105 | {0.245f, 0x46}, | ||
| 106 | {0.251f, 0x48}, | ||
| 107 | {0.256f, 0x4a}, | ||
| 108 | {0.262f, 0x4c}, | ||
| 109 | {0.268f, 0x4e}, | ||
| 110 | {0.273f, 0x50}, | ||
| 111 | {0.279f, 0x52}, | ||
| 112 | {0.286f, 0x54}, | ||
| 113 | {0.292f, 0x56}, | ||
| 114 | {0.298f, 0x58}, | ||
| 115 | {0.305f, 0x5a}, | ||
| 116 | {0.311f, 0x5c}, | ||
| 117 | {0.318f, 0x5e}, | ||
| 118 | {0.325f, 0x60}, | ||
| 119 | {0.332f, 0x62}, | ||
| 120 | {0.34f, 0x64}, | ||
| 121 | {0.347f, 0x66}, | ||
| 122 | {0.355f, 0x68}, | ||
| 123 | {0.362f, 0x6a}, | ||
| 124 | {0.37f, 0x6c}, | ||
| 125 | {0.378f, 0x6e}, | ||
| 126 | {0.387f, 0x70}, | ||
| 127 | {0.395f, 0x72}, | ||
| 128 | {0.404f, 0x74}, | ||
| 129 | {0.413f, 0x76}, | ||
| 130 | {0.422f, 0x78}, | ||
| 131 | {0.431f, 0x7a}, | ||
| 132 | {0.44f, 0x7c}, | ||
| 133 | {0.45f, 0x7e}, | ||
| 134 | {0.46f, 0x80}, | ||
| 135 | {0.47f, 0x82}, | ||
| 136 | {0.48f, 0x84}, | ||
| 137 | {0.491f, 0x86}, | ||
| 138 | {0.501f, 0x88}, | ||
| 139 | {0.512f, 0x8a}, | ||
| 140 | {0.524f, 0x8c}, | ||
| 141 | {0.535f, 0x8e}, | ||
| 142 | {0.547f, 0x90}, | ||
| 143 | {0.559f, 0x92}, | ||
| 144 | {0.571f, 0x94}, | ||
| 145 | {0.584f, 0x96}, | ||
| 146 | {0.596f, 0x98}, | ||
| 147 | {0.609f, 0x9a}, | ||
| 148 | {0.623f, 0x9c}, | ||
| 149 | {0.636f, 0x9e}, | ||
| 150 | {0.65f, 0xa0}, | ||
| 151 | {0.665f, 0xa2}, | ||
| 152 | {0.679f, 0xa4}, | ||
| 153 | {0.694f, 0xa6}, | ||
| 154 | {0.709f, 0xa8}, | ||
| 155 | {0.725f, 0xaa}, | ||
| 156 | {0.741f, 0xac}, | ||
| 157 | {0.757f, 0xae}, | ||
| 158 | {0.773f, 0xb0}, | ||
| 159 | {0.79f, 0xb2}, | ||
| 160 | {0.808f, 0xb4}, | ||
| 161 | {0.825f, 0xb6}, | ||
| 162 | {0.843f, 0xb8}, | ||
| 163 | {0.862f, 0xba}, | ||
| 164 | {0.881f, 0xbc}, | ||
| 165 | {0.9f, 0xbe}, | ||
| 166 | {0.92f, 0xc0}, | ||
| 167 | {0.94f, 0xc2}, | ||
| 168 | {0.96f, 0xc4}, | ||
| 169 | {0.981f, 0xc6}, | ||
| 170 | {1.003f, 0xc8}, | ||
| 171 | }; | ||
| 172 | |||
| 173 | for (const auto& [amplitude_value, code] : high_fequency_amplitude) { | ||
| 174 | if (amplitude <= amplitude_value) { | ||
| 175 | return static_cast<u8>(code); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | return static_cast<u8>(high_fequency_amplitude[high_fequency_amplitude.size() - 1].second); | ||
| 180 | } | ||
| 181 | |||
| 182 | u16 RumbleProtocol::EncodeLowAmplitude(f32 amplitude) const { | ||
| 183 | /* More information about these values can be found here: | ||
| 184 | * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md | ||
| 185 | */ | ||
| 186 | constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ | ||
| 187 | std::pair<f32, int>{0.0f, 0x0040}, | ||
| 188 | {0.01f, 0x8040}, | ||
| 189 | {0.012f, 0x0041}, | ||
| 190 | {0.014f, 0x8041}, | ||
| 191 | {0.017f, 0x0042}, | ||
| 192 | {0.02f, 0x8042}, | ||
| 193 | {0.024f, 0x0043}, | ||
| 194 | {0.028f, 0x8043}, | ||
| 195 | {0.033f, 0x0044}, | ||
| 196 | {0.04f, 0x8044}, | ||
| 197 | {0.047f, 0x0045}, | ||
| 198 | {0.056f, 0x8045}, | ||
| 199 | {0.067f, 0x0046}, | ||
| 200 | {0.08f, 0x8046}, | ||
| 201 | {0.095f, 0x0047}, | ||
| 202 | {0.112f, 0x8047}, | ||
| 203 | {0.117f, 0x0048}, | ||
| 204 | {0.123f, 0x8048}, | ||
| 205 | {0.128f, 0x0049}, | ||
| 206 | {0.134f, 0x8049}, | ||
| 207 | {0.14f, 0x004a}, | ||
| 208 | {0.146f, 0x804a}, | ||
| 209 | {0.152f, 0x004b}, | ||
| 210 | {0.159f, 0x804b}, | ||
| 211 | {0.166f, 0x004c}, | ||
| 212 | {0.173f, 0x804c}, | ||
| 213 | {0.181f, 0x004d}, | ||
| 214 | {0.189f, 0x804d}, | ||
| 215 | {0.198f, 0x004e}, | ||
| 216 | {0.206f, 0x804e}, | ||
| 217 | {0.215f, 0x004f}, | ||
| 218 | {0.225f, 0x804f}, | ||
| 219 | {0.23f, 0x0050}, | ||
| 220 | {0.235f, 0x8050}, | ||
| 221 | {0.24f, 0x0051}, | ||
| 222 | {0.245f, 0x8051}, | ||
| 223 | {0.251f, 0x0052}, | ||
| 224 | {0.256f, 0x8052}, | ||
| 225 | {0.262f, 0x0053}, | ||
| 226 | {0.268f, 0x8053}, | ||
| 227 | {0.273f, 0x0054}, | ||
| 228 | {0.279f, 0x8054}, | ||
| 229 | {0.286f, 0x0055}, | ||
| 230 | {0.292f, 0x8055}, | ||
| 231 | {0.298f, 0x0056}, | ||
| 232 | {0.305f, 0x8056}, | ||
| 233 | {0.311f, 0x0057}, | ||
| 234 | {0.318f, 0x8057}, | ||
| 235 | {0.325f, 0x0058}, | ||
| 236 | {0.332f, 0x8058}, | ||
| 237 | {0.34f, 0x0059}, | ||
| 238 | {0.347f, 0x8059}, | ||
| 239 | {0.355f, 0x005a}, | ||
| 240 | {0.362f, 0x805a}, | ||
| 241 | {0.37f, 0x005b}, | ||
| 242 | {0.378f, 0x805b}, | ||
| 243 | {0.387f, 0x005c}, | ||
| 244 | {0.395f, 0x805c}, | ||
| 245 | {0.404f, 0x005d}, | ||
| 246 | {0.413f, 0x805d}, | ||
| 247 | {0.422f, 0x005e}, | ||
| 248 | {0.431f, 0x805e}, | ||
| 249 | {0.44f, 0x005f}, | ||
| 250 | {0.45f, 0x805f}, | ||
| 251 | {0.46f, 0x0060}, | ||
| 252 | {0.47f, 0x8060}, | ||
| 253 | {0.48f, 0x0061}, | ||
| 254 | {0.491f, 0x8061}, | ||
| 255 | {0.501f, 0x0062}, | ||
| 256 | {0.512f, 0x8062}, | ||
| 257 | {0.524f, 0x0063}, | ||
| 258 | {0.535f, 0x8063}, | ||
| 259 | {0.547f, 0x0064}, | ||
| 260 | {0.559f, 0x8064}, | ||
| 261 | {0.571f, 0x0065}, | ||
| 262 | {0.584f, 0x8065}, | ||
| 263 | {0.596f, 0x0066}, | ||
| 264 | {0.609f, 0x8066}, | ||
| 265 | {0.623f, 0x0067}, | ||
| 266 | {0.636f, 0x8067}, | ||
| 267 | {0.65f, 0x0068}, | ||
| 268 | {0.665f, 0x8068}, | ||
| 269 | {0.679f, 0x0069}, | ||
| 270 | {0.694f, 0x8069}, | ||
| 271 | {0.709f, 0x006a}, | ||
| 272 | {0.725f, 0x806a}, | ||
| 273 | {0.741f, 0x006b}, | ||
| 274 | {0.757f, 0x806b}, | ||
| 275 | {0.773f, 0x006c}, | ||
| 276 | {0.79f, 0x806c}, | ||
| 277 | {0.808f, 0x006d}, | ||
| 278 | {0.825f, 0x806d}, | ||
| 279 | {0.843f, 0x006e}, | ||
| 280 | {0.862f, 0x806e}, | ||
| 281 | {0.881f, 0x006f}, | ||
| 282 | {0.9f, 0x806f}, | ||
| 283 | {0.92f, 0x0070}, | ||
| 284 | {0.94f, 0x8070}, | ||
| 285 | {0.96f, 0x0071}, | ||
| 286 | {0.981f, 0x8071}, | ||
| 287 | {1.003f, 0x0072}, | ||
| 288 | }; | ||
| 289 | |||
| 290 | for (const auto& [amplitude_value, code] : high_fequency_amplitude) { | ||
| 291 | if (amplitude <= amplitude_value) { | ||
| 292 | return static_cast<u16>(code); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | return static_cast<u16>(high_fequency_amplitude[high_fequency_amplitude.size() - 1].second); | ||
| 297 | } | ||
| 298 | |||
| 299 | } // namespace InputCommon::Joycon | ||