ringcon.cpp 8.4 KB

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