ringcon.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "core/hid/emulated_controller.h"
  5. #include "core/hid/hid_core.h"
  6. #include "core/hle/kernel/k_event.h"
  7. #include "core/hle/kernel/k_readable_event.h"
  8. #include "core/hle/service/hid/hidbus/ringcon.h"
  9. namespace Service::HID {
  10. RingController::RingController(Core::HID::HIDCore& hid_core_,
  11. KernelHelpers::ServiceContext& service_context_)
  12. : HidbusBase(service_context_) {
  13. // Use the horizontal axis of left stick for emulating input
  14. // There is no point on adding a frontend implementation since Ring Fit Adventure doesn't work
  15. input = hid_core_.GetEmulatedController(Core::HID::NpadIdType::Player1);
  16. }
  17. RingController::~RingController() = default;
  18. void RingController::OnInit() {
  19. return;
  20. }
  21. void RingController::OnRelease() {
  22. return;
  23. };
  24. void RingController::OnUpdate() {
  25. if (!is_activated) {
  26. return;
  27. }
  28. if (!device_enabled) {
  29. return;
  30. }
  31. if (!polling_mode_enabled || !is_transfer_memory_set) {
  32. return;
  33. }
  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 stick_value = static_cast<f32>(input->GetSticks().left.x) / 32767.0f;
  62. ringcon_sensor_value.data = static_cast<s16>(stick_value * range) + 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::SaveCalData:
  88. return GetSaveDataReply();
  89. default:
  90. return GetErrorReply();
  91. }
  92. }
  93. bool RingController::SetCommand(const std::vector<u8>& data) {
  94. if (data.size() < 4) {
  95. LOG_ERROR(Service_HID, "Command size not supported {}", data.size());
  96. command = RingConCommands::Error;
  97. return false;
  98. }
  99. // There must be a better way to do this
  100. const u32 command_id =
  101. u32{data[0]} + (u32{data[1]} << 8) + (u32{data[2]} << 16) + (u32{data[3]} << 24);
  102. static constexpr std::array supported_commands = {
  103. RingConCommands::GetFirmwareVersion,
  104. RingConCommands::ReadId,
  105. RingConCommands::c20105,
  106. RingConCommands::ReadUnkCal,
  107. RingConCommands::ReadFactoryCal,
  108. RingConCommands::ReadUserCal,
  109. RingConCommands::ReadRepCount,
  110. RingConCommands::ReadTotalPushCount,
  111. RingConCommands::SaveCalData,
  112. };
  113. for (RingConCommands cmd : supported_commands) {
  114. if (command_id == static_cast<u32>(cmd)) {
  115. return ExcecuteCommand(cmd, data);
  116. }
  117. }
  118. LOG_ERROR(Service_HID, "Command not implemented {}", command_id);
  119. command = RingConCommands::Error;
  120. // Signal a reply to avoid softlocking
  121. send_command_asyc_event->GetWritableEvent().Signal();
  122. return false;
  123. }
  124. bool RingController::ExcecuteCommand(RingConCommands cmd, const std::vector<u8>& data) {
  125. switch (cmd) {
  126. case RingConCommands::GetFirmwareVersion:
  127. case RingConCommands::ReadId:
  128. case RingConCommands::c20105:
  129. case RingConCommands::ReadUnkCal:
  130. case RingConCommands::ReadFactoryCal:
  131. case RingConCommands::ReadUserCal:
  132. case RingConCommands::ReadRepCount:
  133. case RingConCommands::ReadTotalPushCount:
  134. ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
  135. command = cmd;
  136. send_command_asyc_event->GetWritableEvent().Signal();
  137. return true;
  138. case RingConCommands::SaveCalData: {
  139. ASSERT_MSG(data.size() == 0x14, "data.size is not 0x14 bytes");
  140. SaveCalData save_info{};
  141. std::memcpy(&save_info, &data, sizeof(SaveCalData));
  142. user_calibration = save_info.calibration;
  143. command = cmd;
  144. send_command_asyc_event->GetWritableEvent().Signal();
  145. return true;
  146. }
  147. default:
  148. LOG_ERROR(Service_HID, "Command not implemented {}", cmd);
  149. command = RingConCommands::Error;
  150. return false;
  151. }
  152. }
  153. std::vector<u8> RingController::GetFirmwareVersionReply() const {
  154. const FirmwareVersionReply reply{
  155. .status = DataValid::Valid,
  156. .firmware = version,
  157. };
  158. return GetDataVector(reply);
  159. }
  160. std::vector<u8> RingController::GetReadIdReply() const {
  161. // The values are hardcoded from a real joycon
  162. const ReadIdReply reply{
  163. .status = DataValid::Valid,
  164. .id_l_x0 = 8,
  165. .id_l_x0_2 = 41,
  166. .id_l_x4 = 22294,
  167. .id_h_x0 = 19777,
  168. .id_h_x0_2 = 13621,
  169. .id_h_x4 = 8245,
  170. };
  171. return GetDataVector(reply);
  172. }
  173. std::vector<u8> RingController::GetC020105Reply() const {
  174. const Cmd020105Reply reply{
  175. .status = DataValid::Valid,
  176. .data = 1,
  177. };
  178. return GetDataVector(reply);
  179. }
  180. std::vector<u8> RingController::GetReadUnkCalReply() const {
  181. const ReadUnkCalReply reply{
  182. .status = DataValid::Valid,
  183. .data = 0,
  184. };
  185. return GetDataVector(reply);
  186. }
  187. std::vector<u8> RingController::GetReadFactoryCalReply() const {
  188. const ReadFactoryCalReply reply{
  189. .status = DataValid::Valid,
  190. .calibration = factory_calibration,
  191. };
  192. return GetDataVector(reply);
  193. }
  194. std::vector<u8> RingController::GetReadUserCalReply() const {
  195. const ReadUserCalReply reply{
  196. .status = DataValid::Valid,
  197. .calibration = user_calibration,
  198. };
  199. return GetDataVector(reply);
  200. }
  201. std::vector<u8> RingController::GetReadRepCountReply() const {
  202. // The values are hardcoded from a real joycon
  203. const GetThreeByteReply reply{
  204. .status = DataValid::Valid,
  205. .data = {30, 0, 0},
  206. .crc = GetCrcValue({30, 0, 0, 0}),
  207. };
  208. return GetDataVector(reply);
  209. }
  210. std::vector<u8> RingController::GetReadTotalPushCountReply() const {
  211. // The values are hardcoded from a real joycon
  212. const GetThreeByteReply reply{
  213. .status = DataValid::Valid,
  214. .data = {30, 0, 0},
  215. .crc = GetCrcValue({30, 0, 0, 0}),
  216. };
  217. return GetDataVector(reply);
  218. }
  219. std::vector<u8> RingController::GetSaveDataReply() const {
  220. const StatusReply reply{
  221. .status = DataValid::Valid,
  222. };
  223. return GetDataVector(reply);
  224. }
  225. std::vector<u8> RingController::GetErrorReply() const {
  226. const ErrorReply reply{
  227. .status = DataValid::BadCRC,
  228. };
  229. return GetDataVector(reply);
  230. }
  231. u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
  232. u8 crc = 0;
  233. for (std::size_t index = 0; index < data.size(); index++) {
  234. for (u8 i = 0x80; i > 0; i >>= 1) {
  235. bool bit = (crc & 0x80) != 0;
  236. if ((data[index] & i) != 0) {
  237. bit = !bit;
  238. }
  239. crc <<= 1;
  240. if (bit) {
  241. crc ^= 0x8d;
  242. }
  243. }
  244. }
  245. return crc;
  246. }
  247. template <typename T>
  248. std::vector<u8> RingController::GetDataVector(const T& reply) const {
  249. static_assert(std::is_trivially_copyable_v<T>);
  250. std::vector<u8> data;
  251. data.resize(sizeof(reply));
  252. std::memcpy(data.data(), &reply, sizeof(reply));
  253. return data;
  254. }
  255. } // namespace Service::HID