joycon_driver.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/logging/log.h"
  4. #include "common/swap.h"
  5. #include "common/thread.h"
  6. #include "input_common/helpers/joycon_driver.h"
  7. namespace InputCommon::Joycon {
  8. JoyconDriver::JoyconDriver(std::size_t port_) : port{port_} {
  9. hidapi_handle = std::make_shared<JoyconHandle>();
  10. }
  11. JoyconDriver::~JoyconDriver() {
  12. Stop();
  13. }
  14. void JoyconDriver::Stop() {
  15. is_connected = false;
  16. input_thread = {};
  17. }
  18. DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
  19. std::scoped_lock lock{mutex};
  20. handle_device_type = ControllerType::None;
  21. GetDeviceType(device_info, handle_device_type);
  22. if (handle_device_type == ControllerType::None) {
  23. return DriverResult::UnsupportedControllerType;
  24. }
  25. hidapi_handle->handle =
  26. SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number);
  27. std::memcpy(&handle_serial_number, device_info->serial_number, 15);
  28. if (!hidapi_handle->handle) {
  29. LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
  30. device_info->vendor_id, device_info->product_id);
  31. return DriverResult::HandleInUse;
  32. }
  33. SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
  34. return DriverResult::Success;
  35. }
  36. DriverResult JoyconDriver::InitializeDevice() {
  37. if (!hidapi_handle->handle) {
  38. return DriverResult::InvalidHandle;
  39. }
  40. std::scoped_lock lock{mutex};
  41. disable_input_thread = true;
  42. // Reset Counters
  43. error_counter = 0;
  44. hidapi_handle->packet_counter = 0;
  45. // Set HW default configuration
  46. vibration_enabled = true;
  47. motion_enabled = true;
  48. hidbus_enabled = false;
  49. nfc_enabled = false;
  50. passive_enabled = false;
  51. gyro_sensitivity = Joycon::GyroSensitivity::DPS2000;
  52. gyro_performance = Joycon::GyroPerformance::HZ833;
  53. accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8;
  54. accelerometer_performance = Joycon::AccelerometerPerformance::HZ100;
  55. // Initialize HW Protocols
  56. calibration_protocol = std::make_unique<CalibrationProtocol>(hidapi_handle);
  57. generic_protocol = std::make_unique<GenericProtocol>(hidapi_handle);
  58. rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
  59. // Get fixed joycon info
  60. generic_protocol->GetVersionNumber(version);
  61. generic_protocol->GetColor(color);
  62. if (handle_device_type == ControllerType::Pro) {
  63. // Some 3rd party controllers aren't pro controllers
  64. generic_protocol->GetControllerType(device_type);
  65. } else {
  66. device_type = handle_device_type;
  67. }
  68. generic_protocol->GetSerialNumber(serial_number);
  69. supported_features = GetSupportedFeatures();
  70. // Get Calibration data
  71. calibration_protocol->GetLeftJoyStickCalibration(left_stick_calibration);
  72. calibration_protocol->GetRightJoyStickCalibration(right_stick_calibration);
  73. calibration_protocol->GetImuCalibration(motion_calibration);
  74. // Set led status
  75. generic_protocol->SetLedBlinkPattern(static_cast<u8>(1 + port));
  76. // Apply HW configuration
  77. SetPollingMode();
  78. // Initialize joycon poller
  79. joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration,
  80. right_stick_calibration, motion_calibration);
  81. // Start pooling for data
  82. is_connected = true;
  83. if (!input_thread_running) {
  84. input_thread =
  85. std::jthread([this](std::stop_token stop_token) { InputThread(stop_token); });
  86. }
  87. disable_input_thread = false;
  88. return DriverResult::Success;
  89. }
  90. void JoyconDriver::InputThread(std::stop_token stop_token) {
  91. LOG_INFO(Input, "JC Adapter input thread started");
  92. Common::SetCurrentThreadName("JoyconInput");
  93. input_thread_running = true;
  94. // Max update rate is 5ms, ensure we are always able to read a bit faster
  95. constexpr int ThreadDelay = 2;
  96. std::vector<u8> buffer(MaxBufferSize);
  97. while (!stop_token.stop_requested()) {
  98. int status = 0;
  99. if (!IsInputThreadValid()) {
  100. input_thread.request_stop();
  101. continue;
  102. }
  103. // By disabling the input thread we can ensure custom commands will succeed as no package is
  104. // skipped
  105. if (!disable_input_thread) {
  106. status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(),
  107. ThreadDelay);
  108. } else {
  109. std::this_thread::sleep_for(std::chrono::milliseconds(ThreadDelay));
  110. }
  111. if (IsPayloadCorrect(status, buffer)) {
  112. OnNewData(buffer);
  113. }
  114. std::this_thread::yield();
  115. }
  116. is_connected = false;
  117. input_thread_running = false;
  118. LOG_INFO(Input, "JC Adapter input thread stopped");
  119. }
  120. void JoyconDriver::OnNewData(std::span<u8> buffer) {
  121. const auto report_mode = static_cast<InputReport>(buffer[0]);
  122. // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion
  123. // experience
  124. switch (report_mode) {
  125. case InputReport::STANDARD_FULL_60HZ:
  126. case InputReport::NFC_IR_MODE_60HZ:
  127. case InputReport::SIMPLE_HID_MODE: {
  128. const auto now = std::chrono::steady_clock::now();
  129. const auto new_delta_time = static_cast<u64>(
  130. std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
  131. delta_time = ((delta_time * 8) + (new_delta_time * 2)) / 10;
  132. last_update = now;
  133. joycon_poller->UpdateColor(color);
  134. break;
  135. }
  136. default:
  137. break;
  138. }
  139. const MotionStatus motion_status{
  140. .is_enabled = motion_enabled,
  141. .delta_time = delta_time,
  142. .gyro_sensitivity = gyro_sensitivity,
  143. .accelerometer_sensitivity = accelerometer_sensitivity,
  144. };
  145. switch (report_mode) {
  146. case InputReport::STANDARD_FULL_60HZ:
  147. joycon_poller->ReadActiveMode(buffer, motion_status);
  148. break;
  149. case InputReport::NFC_IR_MODE_60HZ:
  150. joycon_poller->ReadNfcIRMode(buffer, motion_status);
  151. break;
  152. case InputReport::SIMPLE_HID_MODE:
  153. joycon_poller->ReadPassiveMode(buffer);
  154. break;
  155. case InputReport::SUBCMD_REPLY:
  156. LOG_DEBUG(Input, "Unhandled command reply");
  157. break;
  158. default:
  159. LOG_ERROR(Input, "Report mode not Implemented {}", report_mode);
  160. break;
  161. }
  162. }
  163. void JoyconDriver::SetPollingMode() {
  164. disable_input_thread = true;
  165. rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration);
  166. if (motion_enabled && supported_features.motion) {
  167. generic_protocol->EnableImu(true);
  168. generic_protocol->SetImuConfig(gyro_sensitivity, gyro_performance,
  169. accelerometer_sensitivity, accelerometer_performance);
  170. } else {
  171. generic_protocol->EnableImu(false);
  172. }
  173. if (passive_enabled && supported_features.passive) {
  174. const auto result = generic_protocol->EnablePassiveMode();
  175. if (result == DriverResult::Success) {
  176. disable_input_thread = false;
  177. return;
  178. }
  179. LOG_ERROR(Input, "Error enabling passive mode");
  180. }
  181. // Default Mode
  182. const auto result = generic_protocol->EnableActiveMode();
  183. if (result != DriverResult::Success) {
  184. LOG_ERROR(Input, "Error enabling active mode");
  185. }
  186. disable_input_thread = false;
  187. }
  188. JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() {
  189. SupportedFeatures features{
  190. .passive = true,
  191. .motion = true,
  192. .vibration = true,
  193. };
  194. if (device_type == ControllerType::Right) {
  195. features.nfc = true;
  196. features.irs = true;
  197. features.hidbus = true;
  198. }
  199. if (device_type == ControllerType::Pro) {
  200. features.nfc = true;
  201. }
  202. return features;
  203. }
  204. bool JoyconDriver::IsInputThreadValid() const {
  205. if (!is_connected) {
  206. return false;
  207. }
  208. if (hidapi_handle->handle == nullptr) {
  209. return false;
  210. }
  211. // Controller is not responding. Terminate connection
  212. if (error_counter > MaxErrorCount) {
  213. return false;
  214. }
  215. return true;
  216. }
  217. bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
  218. if (status <= -1) {
  219. error_counter++;
  220. return false;
  221. }
  222. // There's no new data
  223. if (status == 0) {
  224. return false;
  225. }
  226. // No reply ever starts with zero
  227. if (buffer[0] == 0x00) {
  228. error_counter++;
  229. return false;
  230. }
  231. error_counter = 0;
  232. return true;
  233. }
  234. DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
  235. std::scoped_lock lock{mutex};
  236. if (disable_input_thread) {
  237. return DriverResult::HandleInUse;
  238. }
  239. return rumble_protocol->SendVibration(vibration);
  240. }
  241. DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
  242. std::scoped_lock lock{mutex};
  243. if (disable_input_thread) {
  244. return DriverResult::HandleInUse;
  245. }
  246. return generic_protocol->SetLedPattern(led_pattern);
  247. }
  248. DriverResult JoyconDriver::SetPasiveMode() {
  249. std::scoped_lock lock{mutex};
  250. motion_enabled = false;
  251. hidbus_enabled = false;
  252. nfc_enabled = false;
  253. passive_enabled = true;
  254. SetPollingMode();
  255. return DriverResult::Success;
  256. }
  257. DriverResult JoyconDriver::SetActiveMode() {
  258. std::scoped_lock lock{mutex};
  259. motion_enabled = true;
  260. hidbus_enabled = false;
  261. nfc_enabled = false;
  262. passive_enabled = false;
  263. SetPollingMode();
  264. return DriverResult::Success;
  265. }
  266. DriverResult JoyconDriver::SetNfcMode() {
  267. std::scoped_lock lock{mutex};
  268. motion_enabled = false;
  269. hidbus_enabled = false;
  270. nfc_enabled = true;
  271. passive_enabled = false;
  272. SetPollingMode();
  273. return DriverResult::Success;
  274. }
  275. DriverResult JoyconDriver::SetRingConMode() {
  276. std::scoped_lock lock{mutex};
  277. motion_enabled = true;
  278. hidbus_enabled = true;
  279. nfc_enabled = false;
  280. passive_enabled = false;
  281. SetPollingMode();
  282. return DriverResult::Success;
  283. }
  284. bool JoyconDriver::IsConnected() const {
  285. std::scoped_lock lock{mutex};
  286. return is_connected;
  287. }
  288. bool JoyconDriver::IsVibrationEnabled() const {
  289. std::scoped_lock lock{mutex};
  290. return vibration_enabled;
  291. }
  292. FirmwareVersion JoyconDriver::GetDeviceVersion() const {
  293. std::scoped_lock lock{mutex};
  294. return version;
  295. }
  296. Color JoyconDriver::GetDeviceColor() const {
  297. std::scoped_lock lock{mutex};
  298. return color;
  299. }
  300. std::size_t JoyconDriver::GetDevicePort() const {
  301. std::scoped_lock lock{mutex};
  302. return port;
  303. }
  304. ControllerType JoyconDriver::GetDeviceType() const {
  305. std::scoped_lock lock{mutex};
  306. return device_type;
  307. }
  308. ControllerType JoyconDriver::GetHandleDeviceType() const {
  309. std::scoped_lock lock{mutex};
  310. return handle_device_type;
  311. }
  312. SerialNumber JoyconDriver::GetSerialNumber() const {
  313. std::scoped_lock lock{mutex};
  314. return serial_number;
  315. }
  316. SerialNumber JoyconDriver::GetHandleSerialNumber() const {
  317. std::scoped_lock lock{mutex};
  318. return handle_serial_number;
  319. }
  320. void JoyconDriver::SetCallbacks(const Joycon::JoyconCallbacks& callbacks) {
  321. joycon_poller->SetCallbacks(callbacks);
  322. }
  323. Joycon::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
  324. ControllerType& controller_type) {
  325. std::array<std::pair<u32, Joycon::ControllerType>, 4> supported_devices{
  326. std::pair<u32, Joycon::ControllerType>{0x2006, Joycon::ControllerType::Left},
  327. {0x2007, Joycon::ControllerType::Right},
  328. {0x2009, Joycon::ControllerType::Pro},
  329. {0x200E, Joycon::ControllerType::Grip},
  330. };
  331. constexpr u16 nintendo_vendor_id = 0x057e;
  332. controller_type = Joycon::ControllerType::None;
  333. if (device_info->vendor_id != nintendo_vendor_id) {
  334. return Joycon::DriverResult::UnsupportedControllerType;
  335. }
  336. for (const auto& [product_id, type] : supported_devices) {
  337. if (device_info->product_id == static_cast<u16>(product_id)) {
  338. controller_type = type;
  339. return Joycon::DriverResult::Success;
  340. }
  341. }
  342. return Joycon::DriverResult::UnsupportedControllerType;
  343. }
  344. Joycon::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
  345. Joycon::SerialNumber& serial_number) {
  346. if (device_info->serial_number == nullptr) {
  347. return Joycon::DriverResult::Unknown;
  348. }
  349. std::memcpy(&serial_number, device_info->serial_number, 15);
  350. return Joycon::DriverResult::Success;
  351. }
  352. } // namespace InputCommon::Joycon