ringcon.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/hid/emulated_controller.h"
  4. #include "core/hid/hid_core.h"
  5. #include "core/hle/kernel/k_event.h"
  6. #include "core/hle/kernel/k_readable_event.h"
  7. #include "core/hle/service/hid/hidbus/ringcon.h"
  8. namespace Service::HID {
  9. RingController::RingController(Core::HID::HIDCore& hid_core_,
  10. KernelHelpers::ServiceContext& service_context_)
  11. : HidbusBase(service_context_) {
  12. input = hid_core_.GetEmulatedController(Core::HID::NpadIdType::Player1);
  13. }
  14. RingController::~RingController() = default;
  15. void RingController::OnInit() {
  16. input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
  17. Common::Input::PollingMode::Ring);
  18. return;
  19. }
  20. void RingController::OnRelease() {
  21. input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
  22. Common::Input::PollingMode::Active);
  23. return;
  24. };
  25. void RingController::OnUpdate() {
  26. if (!is_activated) {
  27. return;
  28. }
  29. if (!device_enabled) {
  30. return;
  31. }
  32. if (!polling_mode_enabled || !is_transfer_memory_set) {
  33. return;
  34. }
  35. // TODO: Increment multitasking counters from motion and sensor data
  36. switch (polling_mode) {
  37. case JoyPollingMode::SixAxisSensorEnable: {
  38. enable_sixaxis_data.header.total_entries = 10;
  39. enable_sixaxis_data.header.result = ResultSuccess;
  40. const auto& last_entry =
  41. enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry];
  42. enable_sixaxis_data.header.latest_entry =
  43. (enable_sixaxis_data.header.latest_entry + 1) % 10;
  44. auto& curr_entry = enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry];
  45. curr_entry.sampling_number = last_entry.sampling_number + 1;
  46. curr_entry.polling_data.sampling_number = curr_entry.sampling_number;
  47. const RingConData ringcon_value = GetSensorValue();
  48. curr_entry.polling_data.out_size = sizeof(ringcon_value);
  49. std::memcpy(curr_entry.polling_data.data.data(), &ringcon_value, sizeof(ringcon_value));
  50. std::memcpy(transfer_memory, &enable_sixaxis_data, sizeof(enable_sixaxis_data));
  51. break;
  52. }
  53. default:
  54. LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode);
  55. break;
  56. }
  57. }
  58. RingController::RingConData RingController::GetSensorValue() const {
  59. RingConData ringcon_sensor_value{
  60. .status = DataValid::Valid,
  61. .data = 0,
  62. };
  63. const f32 force_value = input->GetRingSensorForce().force * range;
  64. ringcon_sensor_value.data = static_cast<s16>(force_value) + idle_value;
  65. return ringcon_sensor_value;
  66. }
  67. u8 RingController::GetDeviceId() const {
  68. return device_id;
  69. }
  70. std::vector<u8> RingController::GetReply() const {
  71. const RingConCommands current_command = command;
  72. switch (current_command) {
  73. case RingConCommands::GetFirmwareVersion:
  74. return GetFirmwareVersionReply();
  75. case RingConCommands::ReadId:
  76. return GetReadIdReply();
  77. case RingConCommands::c20105:
  78. return GetC020105Reply();
  79. case RingConCommands::ReadUnkCal:
  80. return GetReadUnkCalReply();
  81. case RingConCommands::ReadFactoryCal:
  82. return GetReadFactoryCalReply();
  83. case RingConCommands::ReadUserCal:
  84. return GetReadUserCalReply();
  85. case RingConCommands::ReadRepCount:
  86. return GetReadRepCountReply();
  87. case RingConCommands::ReadTotalPushCount:
  88. return GetReadTotalPushCountReply();
  89. case RingConCommands::ResetRepCount:
  90. return GetResetRepCountReply();
  91. case RingConCommands::SaveCalData:
  92. return GetSaveDataReply();
  93. default:
  94. return GetErrorReply();
  95. }
  96. }
  97. bool RingController::SetCommand(const std::vector<u8>& data) {
  98. if (data.size() < 4) {
  99. LOG_ERROR(Service_HID, "Command size not supported {}", data.size());
  100. command = RingConCommands::Error;
  101. return false;
  102. }
  103. std::memcpy(&command, data.data(), sizeof(RingConCommands));
  104. switch (command) {
  105. case RingConCommands::GetFirmwareVersion:
  106. case RingConCommands::ReadId:
  107. case RingConCommands::c20105:
  108. case RingConCommands::ReadUnkCal:
  109. case RingConCommands::ReadFactoryCal:
  110. case RingConCommands::ReadUserCal:
  111. case RingConCommands::ReadRepCount:
  112. case RingConCommands::ReadTotalPushCount:
  113. ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
  114. send_command_async_event->Signal();
  115. return true;
  116. case RingConCommands::ResetRepCount:
  117. ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
  118. total_rep_count = 0;
  119. send_command_async_event->Signal();
  120. return true;
  121. case RingConCommands::SaveCalData: {
  122. ASSERT_MSG(data.size() == 0x14, "data.size is not 0x14 bytes");
  123. SaveCalData save_info{};
  124. std::memcpy(&save_info, data.data(), sizeof(SaveCalData));
  125. user_calibration = save_info.calibration;
  126. send_command_async_event->Signal();
  127. return true;
  128. }
  129. default:
  130. LOG_ERROR(Service_HID, "Command not implemented {}", command);
  131. command = RingConCommands::Error;
  132. // Signal a reply to avoid softlocking the game
  133. send_command_async_event->Signal();
  134. return false;
  135. }
  136. }
  137. std::vector<u8> RingController::GetFirmwareVersionReply() const {
  138. const FirmwareVersionReply reply{
  139. .status = DataValid::Valid,
  140. .firmware = version,
  141. };
  142. return GetDataVector(reply);
  143. }
  144. std::vector<u8> RingController::GetReadIdReply() const {
  145. // The values are hardcoded from a real joycon
  146. const ReadIdReply reply{
  147. .status = DataValid::Valid,
  148. .id_l_x0 = 8,
  149. .id_l_x0_2 = 41,
  150. .id_l_x4 = 22294,
  151. .id_h_x0 = 19777,
  152. .id_h_x0_2 = 13621,
  153. .id_h_x4 = 8245,
  154. };
  155. return GetDataVector(reply);
  156. }
  157. std::vector<u8> RingController::GetC020105Reply() const {
  158. const Cmd020105Reply reply{
  159. .status = DataValid::Valid,
  160. .data = 1,
  161. };
  162. return GetDataVector(reply);
  163. }
  164. std::vector<u8> RingController::GetReadUnkCalReply() const {
  165. const ReadUnkCalReply reply{
  166. .status = DataValid::Valid,
  167. .data = 0,
  168. };
  169. return GetDataVector(reply);
  170. }
  171. std::vector<u8> RingController::GetReadFactoryCalReply() const {
  172. const ReadFactoryCalReply reply{
  173. .status = DataValid::Valid,
  174. .calibration = factory_calibration,
  175. };
  176. return GetDataVector(reply);
  177. }
  178. std::vector<u8> RingController::GetReadUserCalReply() const {
  179. const ReadUserCalReply reply{
  180. .status = DataValid::Valid,
  181. .calibration = user_calibration,
  182. };
  183. return GetDataVector(reply);
  184. }
  185. std::vector<u8> RingController::GetReadRepCountReply() const {
  186. const GetThreeByteReply reply{
  187. .status = DataValid::Valid,
  188. .data = {total_rep_count, 0, 0},
  189. .crc = GetCrcValue({total_rep_count, 0, 0, 0}),
  190. };
  191. return GetDataVector(reply);
  192. }
  193. std::vector<u8> RingController::GetReadTotalPushCountReply() const {
  194. const GetThreeByteReply reply{
  195. .status = DataValid::Valid,
  196. .data = {total_push_count, 0, 0},
  197. .crc = GetCrcValue({total_push_count, 0, 0, 0}),
  198. };
  199. return GetDataVector(reply);
  200. }
  201. std::vector<u8> RingController::GetResetRepCountReply() const {
  202. return GetReadRepCountReply();
  203. }
  204. std::vector<u8> RingController::GetSaveDataReply() const {
  205. const StatusReply reply{
  206. .status = DataValid::Valid,
  207. };
  208. return GetDataVector(reply);
  209. }
  210. std::vector<u8> RingController::GetErrorReply() const {
  211. const ErrorReply reply{
  212. .status = DataValid::BadCRC,
  213. };
  214. return GetDataVector(reply);
  215. }
  216. u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
  217. u8 crc = 0;
  218. for (std::size_t index = 0; index < data.size(); index++) {
  219. for (u8 i = 0x80; i > 0; i >>= 1) {
  220. bool bit = (crc & 0x80) != 0;
  221. if ((data[index] & i) != 0) {
  222. bit = !bit;
  223. }
  224. crc <<= 1;
  225. if (bit) {
  226. crc ^= 0x8d;
  227. }
  228. }
  229. }
  230. return crc;
  231. }
  232. template <typename T>
  233. std::vector<u8> RingController::GetDataVector(const T& reply) const {
  234. static_assert(std::is_trivially_copyable_v<T>);
  235. std::vector<u8> data;
  236. data.resize(sizeof(reply));
  237. std::memcpy(data.data(), &reply, sizeof(reply));
  238. return data;
  239. }
  240. } // namespace Service::HID