joycon_driver.cpp 15 KB

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