ringcon.cpp 8.2 KB

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