calibration_configuration_job.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <array>
  4. #include <string>
  5. #include <thread>
  6. #include <boost/asio.hpp>
  7. #include <boost/crc.hpp>
  8. #include <catch2/catch_test_macros.hpp>
  9. #include "input_common/drivers/udp_client.h"
  10. #include "input_common/helpers/udp_protocol.h"
  11. class FakeCemuhookServer {
  12. public:
  13. FakeCemuhookServer()
  14. : socket(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)) {}
  15. ~FakeCemuhookServer() {
  16. is_running = false;
  17. boost::system::error_code error_code;
  18. socket.shutdown(boost::asio::socket_base::shutdown_both, error_code);
  19. socket.close();
  20. if (handler.joinable()) {
  21. handler.join();
  22. }
  23. }
  24. u16 GetPort() {
  25. return socket.local_endpoint().port();
  26. }
  27. std::string GetHost() {
  28. return socket.local_endpoint().address().to_string();
  29. }
  30. void Run(const std::vector<InputCommon::CemuhookUDP::Response::TouchPad> touch_movement_path) {
  31. constexpr size_t HeaderSize = sizeof(InputCommon::CemuhookUDP::Header);
  32. constexpr size_t PadDataSize =
  33. sizeof(InputCommon::CemuhookUDP::Message<InputCommon::CemuhookUDP::Response::PadData>);
  34. REQUIRE(touch_movement_path.size() > 0);
  35. is_running = true;
  36. handler = std::thread([touch_movement_path, this]() {
  37. auto current_touch_position = touch_movement_path.begin();
  38. while (is_running) {
  39. boost::asio::ip::udp::endpoint sender_endpoint;
  40. boost::system::error_code error_code;
  41. auto received_size = socket.receive_from(boost::asio::buffer(receive_buffer),
  42. sender_endpoint, 0, error_code);
  43. if (received_size < HeaderSize) {
  44. continue;
  45. }
  46. InputCommon::CemuhookUDP::Header header{};
  47. std::memcpy(&header, receive_buffer.data(), HeaderSize);
  48. switch (header.type) {
  49. case InputCommon::CemuhookUDP::Type::PadData: {
  50. InputCommon::CemuhookUDP::Response::PadData pad_data{};
  51. pad_data.touch[0] = *current_touch_position;
  52. const auto pad_message = InputCommon::CemuhookUDP::CreateMessage(
  53. InputCommon::CemuhookUDP::SERVER_MAGIC, pad_data, 0);
  54. std::memcpy(send_buffer.data(), &pad_message, PadDataSize);
  55. socket.send_to(boost::asio::buffer(send_buffer, PadDataSize), sender_endpoint,
  56. 0, error_code);
  57. bool can_advance =
  58. std::next(current_touch_position) != touch_movement_path.end();
  59. if (can_advance) {
  60. std::advance(current_touch_position, 1);
  61. }
  62. break;
  63. }
  64. case InputCommon::CemuhookUDP::Type::PortInfo:
  65. case InputCommon::CemuhookUDP::Type::Version:
  66. default:
  67. break;
  68. }
  69. }
  70. });
  71. }
  72. private:
  73. boost::asio::io_service io_service;
  74. boost::asio::ip::udp::socket socket;
  75. std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> send_buffer;
  76. std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> receive_buffer;
  77. bool is_running = false;
  78. std::thread handler;
  79. };
  80. TEST_CASE("CalibrationConfigurationJob completed", "[input_common]") {
  81. Common::Event complete_event;
  82. FakeCemuhookServer server;
  83. server.Run({{
  84. .is_active = 1,
  85. .x = 0,
  86. .y = 0,
  87. },
  88. {
  89. .is_active = 1,
  90. .x = 200,
  91. .y = 200,
  92. }});
  93. InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status{};
  94. u16 min_x{};
  95. u16 min_y{};
  96. u16 max_x{};
  97. u16 max_y{};
  98. InputCommon::CemuhookUDP::CalibrationConfigurationJob job(
  99. server.GetHost(), server.GetPort(),
  100. [&status,
  101. &complete_event](InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status_) {
  102. status = status_;
  103. if (status ==
  104. InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed) {
  105. complete_event.Set();
  106. }
  107. },
  108. [&](u16 min_x_, u16 min_y_, u16 max_x_, u16 max_y_) {
  109. min_x = min_x_;
  110. min_y = min_y_;
  111. max_x = max_x_;
  112. max_y = max_y_;
  113. });
  114. complete_event.WaitUntil(std::chrono::system_clock::now() + std::chrono::seconds(10));
  115. REQUIRE(status == InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed);
  116. REQUIRE(min_x == 0);
  117. REQUIRE(min_y == 0);
  118. REQUIRE(max_x == 200);
  119. REQUIRE(max_y == 200);
  120. }