dualshock4_controller_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/gamepad/dualshock4_controller.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/memory/raw_ptr.h"
  8. #include "base/memory/weak_ptr.h"
  9. #include "base/run_loop.h"
  10. #include "base/test/task_environment.h"
  11. #include "device/gamepad/hid_writer.h"
  12. #include "device/gamepad/public/mojom/gamepad.mojom.h"
  13. #include "testing/gmock/include/gmock/gmock.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. namespace device {
  16. namespace {
  17. constexpr size_t kUsbReportLength = 32;
  18. constexpr size_t kBluetoothReportLength = 78;
  19. constexpr uint8_t kUsbStopVibration[] = {
  20. 0x05, // report ID
  21. 0x01, 0x00, 0x00,
  22. 0x00, // weak magnitude
  23. 0x00, // strong magnitude
  24. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  25. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  26. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  27. static_assert(sizeof(kUsbStopVibration) == kUsbReportLength,
  28. "kUsbStopVibration has incorrect size");
  29. constexpr uint8_t kUsbStartVibration[] = {
  30. 0x05, // report ID
  31. 0x01, 0x00, 0x00,
  32. 0x80, // weak magnitude
  33. 0xff, // strong magnitude
  34. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  35. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  36. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  37. static_assert(sizeof(kUsbStartVibration) == kUsbReportLength,
  38. "kUsbStartVibration has incorrect size");
  39. constexpr uint8_t kBtStopVibration[] = {
  40. 0x11, // report ID
  41. 0xc0, 0x20, 0xf1, 0x04, 0x00,
  42. 0x00, // weak magnitude
  43. 0x00, // strong magnitude
  44. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  45. 0x00, 0x43, 0x43, 0x00, 0x4d, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  46. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  47. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  48. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  49. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  50. // CRC32
  51. 0x30, 0x50, 0xad, 0x07};
  52. static_assert(sizeof(kBtStopVibration) == kBluetoothReportLength,
  53. "kBtStopVibration has incorrect size");
  54. constexpr uint8_t kBtStartVibration[] = {
  55. 0x11, // report ID
  56. 0xc0, 0x20, 0xf1, 0x04, 0x00,
  57. 0x80, // weak magnitude
  58. 0xff, // strong magnitude
  59. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  60. 0x00, 0x43, 0x43, 0x00, 0x4d, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  61. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  62. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  63. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  64. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  65. // CRC32
  66. 0x1e, 0x67, 0x45, 0xb4};
  67. static_assert(sizeof(kBtStartVibration) == kBluetoothReportLength,
  68. "kBtStartVibration has incorrect size");
  69. // Use 1 ms for all non-zero effect durations. There is no reason to test longer
  70. // delays as they will be skipped anyway.
  71. constexpr double kDurationMillis = 1.0;
  72. // Setting |start_delay| to zero can cause additional reports to be sent.
  73. constexpr double kZeroStartDelayMillis = 0.0;
  74. // Vibration magnitudes for the strong and weak channels of a typical
  75. // dual-rumble vibration effect. kStartVibrationData describes a report with
  76. // these magnitudes.
  77. constexpr double kStrongMagnitude = 1.0; // 100% intensity
  78. constexpr double kWeakMagnitude = 0.5; // 50% intensity
  79. constexpr base::TimeDelta kPendingTaskDuration =
  80. base::Milliseconds(kDurationMillis);
  81. class FakeHidWriter : public HidWriter {
  82. public:
  83. FakeHidWriter() = default;
  84. ~FakeHidWriter() override = default;
  85. // HidWriter implementation.
  86. size_t WriteOutputReport(base::span<const uint8_t> report) override {
  87. output_reports.emplace_back(report.begin(), report.end());
  88. return report.size_bytes();
  89. }
  90. std::vector<std::vector<uint8_t>> output_reports;
  91. };
  92. // Main test fixture
  93. class Dualshock4ControllerTest : public testing::Test {
  94. public:
  95. Dualshock4ControllerTest()
  96. : usb_start_vibration_report_(kUsbStartVibration,
  97. kUsbStartVibration + kUsbReportLength),
  98. usb_stop_vibration_report_(kUsbStopVibration,
  99. kUsbStopVibration + kUsbReportLength),
  100. bluetooth_start_vibration_report_(
  101. kBtStartVibration,
  102. kBtStartVibration + kBluetoothReportLength),
  103. bluetooth_stop_vibration_report_(
  104. kBtStopVibration,
  105. kBtStopVibration + kBluetoothReportLength),
  106. callback_count_(0),
  107. callback_result_(
  108. mojom::GamepadHapticsResult::GamepadHapticsResultError) {
  109. // Create two Dualshock4Controller instances, one configured for USB and one
  110. // for Bluetooth.
  111. auto usb_writer = std::make_unique<FakeHidWriter>();
  112. usb_writer_ = usb_writer.get();
  113. ds4_usb_ = std::make_unique<Dualshock4Controller>(
  114. GamepadId::kSonyProduct05c4, GAMEPAD_BUS_USB, std::move(usb_writer));
  115. auto bluetooth_writer = std::make_unique<FakeHidWriter>();
  116. bluetooth_writer_ = bluetooth_writer.get();
  117. ds4_bluetooth_ = std::make_unique<Dualshock4Controller>(
  118. GamepadId::kSonyProduct05c4, GAMEPAD_BUS_BLUETOOTH,
  119. std::move(bluetooth_writer));
  120. }
  121. Dualshock4ControllerTest(const Dualshock4ControllerTest&) = delete;
  122. Dualshock4ControllerTest& operator=(const Dualshock4ControllerTest&) = delete;
  123. void TearDown() override {
  124. ds4_usb_->Shutdown();
  125. ds4_bluetooth_->Shutdown();
  126. }
  127. void PostPlayEffect(
  128. Dualshock4Controller* gamepad,
  129. double start_delay,
  130. double strong_magnitude,
  131. double weak_magnitude,
  132. mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
  133. gamepad->PlayEffect(
  134. mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
  135. mojom::GamepadEffectParameters::New(
  136. kDurationMillis, start_delay, strong_magnitude, weak_magnitude,
  137. /*left_trigger=*/0, /*right_trigger=*/0),
  138. std::move(callback), base::ThreadTaskRunnerHandle::Get());
  139. }
  140. void PostResetVibration(
  141. Dualshock4Controller* gamepad,
  142. mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback) {
  143. gamepad->ResetVibration(std::move(callback),
  144. base::ThreadTaskRunnerHandle::Get());
  145. }
  146. // Callback for PlayEffect or ResetVibration.
  147. void Callback(mojom::GamepadHapticsResult result) {
  148. callback_count_++;
  149. callback_result_ = result;
  150. }
  151. const std::vector<uint8_t> usb_start_vibration_report_;
  152. const std::vector<uint8_t> usb_stop_vibration_report_;
  153. const std::vector<uint8_t> bluetooth_start_vibration_report_;
  154. const std::vector<uint8_t> bluetooth_stop_vibration_report_;
  155. int callback_count_;
  156. mojom::GamepadHapticsResult callback_result_;
  157. raw_ptr<FakeHidWriter> usb_writer_;
  158. raw_ptr<FakeHidWriter> bluetooth_writer_;
  159. std::unique_ptr<Dualshock4Controller> ds4_usb_;
  160. std::unique_ptr<Dualshock4Controller> ds4_bluetooth_;
  161. base::test::TaskEnvironment task_environment_{
  162. base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  163. };
  164. TEST_F(Dualshock4ControllerTest, PlayEffectUsb) {
  165. EXPECT_TRUE(usb_writer_->output_reports.empty());
  166. EXPECT_EQ(0, callback_count_);
  167. PostPlayEffect(ds4_usb_.get(), kZeroStartDelayMillis, kStrongMagnitude,
  168. kWeakMagnitude,
  169. base::BindOnce(&Dualshock4ControllerTest::Callback,
  170. base::Unretained(this)));
  171. // Run the queued task and start vibration.
  172. task_environment_.RunUntilIdle();
  173. EXPECT_THAT(usb_writer_->output_reports,
  174. testing::ElementsAre(usb_start_vibration_report_));
  175. EXPECT_EQ(0, callback_count_);
  176. EXPECT_GT(task_environment_.GetPendingMainThreadTaskCount(), 0u);
  177. // Finish the effect.
  178. task_environment_.FastForwardBy(kPendingTaskDuration);
  179. EXPECT_THAT(usb_writer_->output_reports,
  180. testing::ElementsAre(usb_start_vibration_report_));
  181. EXPECT_EQ(1, callback_count_);
  182. EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
  183. callback_result_);
  184. EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
  185. }
  186. TEST_F(Dualshock4ControllerTest, PlayEffectBluetooth) {
  187. EXPECT_TRUE(bluetooth_writer_->output_reports.empty());
  188. EXPECT_EQ(0, callback_count_);
  189. PostPlayEffect(ds4_bluetooth_.get(), kZeroStartDelayMillis, kStrongMagnitude,
  190. kWeakMagnitude,
  191. base::BindOnce(&Dualshock4ControllerTest::Callback,
  192. base::Unretained(this)));
  193. // Run the queued task and start vibration.
  194. task_environment_.RunUntilIdle();
  195. EXPECT_THAT(bluetooth_writer_->output_reports,
  196. testing::ElementsAre(bluetooth_start_vibration_report_));
  197. EXPECT_EQ(0, callback_count_);
  198. EXPECT_GT(task_environment_.GetPendingMainThreadTaskCount(), 0u);
  199. // Finish the effect.
  200. task_environment_.FastForwardBy(kPendingTaskDuration);
  201. EXPECT_THAT(bluetooth_writer_->output_reports,
  202. testing::ElementsAre(bluetooth_start_vibration_report_));
  203. EXPECT_EQ(1, callback_count_);
  204. EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
  205. callback_result_);
  206. EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
  207. }
  208. TEST_F(Dualshock4ControllerTest, ResetVibrationUsb) {
  209. EXPECT_TRUE(usb_writer_->output_reports.empty());
  210. EXPECT_EQ(0, callback_count_);
  211. PostResetVibration(ds4_usb_.get(),
  212. base::BindOnce(&Dualshock4ControllerTest::Callback,
  213. base::Unretained(this)));
  214. // Run the queued task and reset vibration.
  215. task_environment_.RunUntilIdle();
  216. EXPECT_THAT(usb_writer_->output_reports,
  217. testing::ElementsAre(usb_stop_vibration_report_));
  218. EXPECT_EQ(1, callback_count_);
  219. EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
  220. callback_result_);
  221. EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
  222. }
  223. TEST_F(Dualshock4ControllerTest, ResetVibrationBluetooth) {
  224. EXPECT_TRUE(bluetooth_writer_->output_reports.empty());
  225. EXPECT_EQ(0, callback_count_);
  226. PostResetVibration(ds4_bluetooth_.get(),
  227. base::BindOnce(&Dualshock4ControllerTest::Callback,
  228. base::Unretained(this)));
  229. // Run the queued task and reset vibration.
  230. task_environment_.RunUntilIdle();
  231. EXPECT_THAT(bluetooth_writer_->output_reports,
  232. testing::ElementsAre(bluetooth_stop_vibration_report_));
  233. EXPECT_EQ(1, callback_count_);
  234. EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
  235. callback_result_);
  236. EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
  237. }
  238. } // namespace
  239. } // namespace device