Skip to content

Commit c6e24db

Browse files
committed
Add helpers and tests for PS4 sensors
1 parent 40c94dd commit c6e24db

File tree

6 files changed

+128
-0
lines changed

6 files changed

+128
-0
lines changed

WinUHidDevs/WinUHidDevs.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
</PropertyGroup>
5252
<ItemDefinitionGroup>
5353
<ClCompile>
54+
<LanguageStandard>stdcpp20</LanguageStandard>
5455
<WarningLevel>Level3</WarningLevel>
5556
<SDLCheck>true</SDLCheck>
5657
<PreprocessorDefinitions>WINUHID_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>

WinUHidDevs/WinUHidPS4.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "pch.h"
22
#include "WinUHidPS4.h"
33

4+
#include <algorithm>
5+
46
#include <wrl/wrappers/corewrappers.h>
57
using namespace Microsoft::WRL;
68

@@ -700,6 +702,11 @@ WINUHID_API VOID WinUHidPS4InitializeInputReport(PWINUHID_PS4_INPUT_REPORT Repor
700702
WinUHidPS4SetTouchState(Report, 1, FALSE, 0, 0);
701703

702704
WinUHidPS4SetBatteryState(Report, TRUE, 100);
705+
706+
//
707+
// Initialize accelerometer in neutral upright position
708+
//
709+
WinUHidPS4SetAccelState(Report, 0, 9.80665f, 0);
703710
}
704711

705712
WINUHID_API VOID WinUHidPS4SetTouchState(PWINUHID_PS4_INPUT_REPORT Report, UCHAR TouchIndex, BOOL TouchDown, USHORT TouchX, USHORT TouchY)
@@ -719,6 +726,24 @@ WINUHID_API VOID WinUHidPS4SetTouchState(PWINUHID_PS4_INPUT_REPORT Report, UCHAR
719726
Report->TouchReports[0].Timestamp++;
720727
}
721728

729+
WINUHID_API VOID WinUHidPS4SetAccelState(PWINUHID_PS4_INPUT_REPORT Report, float AccelX, float AccelY, float AccelZ)
730+
{
731+
static const float k_AccelSensitivity = 0.000980664976f;
732+
733+
Report->AccelX = std::clamp((int)(AccelX / k_AccelSensitivity), SHRT_MIN, SHRT_MAX);
734+
Report->AccelY = std::clamp((int)(AccelY / k_AccelSensitivity), SHRT_MIN, SHRT_MAX);
735+
Report->AccelZ = std::clamp((int)(AccelZ / k_AccelSensitivity), SHRT_MIN, SHRT_MAX);
736+
}
737+
738+
WINUHID_API VOID WinUHidPS4SetGyroState(PWINUHID_PS4_INPUT_REPORT Report, float GyroX, float GyroY, float GyroZ)
739+
{
740+
static const float k_GyroSensitivity = 0.000872664619f;
741+
742+
Report->GyroX = std::clamp((int)(GyroX / k_GyroSensitivity), SHRT_MIN, SHRT_MAX);
743+
Report->GyroY = std::clamp((int)(GyroY / k_GyroSensitivity), SHRT_MIN, SHRT_MAX);
744+
Report->GyroZ = std::clamp((int)(GyroZ / k_GyroSensitivity), SHRT_MIN, SHRT_MAX);
745+
}
746+
722747
WINUHID_API VOID WinUHidPS4SetBatteryState(PWINUHID_PS4_INPUT_REPORT Report, BOOL Wired, UCHAR Percentage)
723748
{
724749
if (Percentage == 100 && Wired) {

WinUHidDevs/WinUHidPS4.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,20 @@ WINUHID_API VOID WinUHidPS4SetBatteryState(PWINUHID_PS4_INPUT_REPORT Report, BOO
131131
//
132132
WINUHID_API VOID WinUHidPS4SetTouchState(PWINUHID_PS4_INPUT_REPORT Report, UCHAR TouchIndex, BOOL TouchDown, USHORT TouchX, USHORT TouchY);
133133

134+
//
135+
// Sets the accelerometer state in the input report.
136+
//
137+
// The values provided should be in meters per second squared.
138+
//
139+
WINUHID_API VOID WinUHidPS4SetAccelState(PWINUHID_PS4_INPUT_REPORT Report, float AccelX, float AccelY, float AccelZ);
140+
141+
//
142+
// Sets the gyroscope state in the input report.
143+
//
144+
// The values provided should be in radians per second.
145+
//
146+
WINUHID_API VOID WinUHidPS4SetGyroState(PWINUHID_PS4_INPUT_REPORT Report, float GyroX, float GyroY, float GyroZ);
147+
134148
//
135149
// Submits an input report to the device.
136150
//

WinUHidUnitTests/PS4.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,73 @@ TEST(PS4, AxisMapping) {
182182
WinUHidPS4Destroy(gamepad);
183183
}
184184

185+
TEST(PS4, SensorMapping) {
186+
auto gamepad = WinUHidPS4Create(NULL, NULL, NULL, NULL);
187+
ASSERT_TRUE(gamepad) << "Failed to create PS4 gamepad";
188+
189+
SDLGamepadManager gm;
190+
ASSERT_EQ(gm.GetGamepadCount(), 1) << "Unable to detect PS4 gamepad with SDL";
191+
192+
//
193+
// Sensors must be enabled before they can be read
194+
//
195+
ASSERT_TRUE(SDL_SetGamepadSensorEnabled(gm.GetGamepad(0), SDL_SENSOR_GYRO, true));
196+
ASSERT_TRUE(SDL_SetGamepadSensorEnabled(gm.GetGamepad(0), SDL_SENSOR_ACCEL, true));
197+
198+
WINUHID_PS4_INPUT_REPORT report;
199+
WinUHidPS4InitializeInputReport(&report);
200+
201+
for (float value = -28; value <= 28; value += 0.25) {
202+
WinUHidPS4SetGyroState(&report, value, 0, 0);
203+
ASSERT_EQ(WinUHidPS4ReportInput(gamepad, &report), TRUE);
204+
205+
float expected[3] = { value, 0, 0 };
206+
gm.ExpectSensorData(SDL_SENSOR_GYRO, expected);
207+
}
208+
209+
for (float value = -28; value <= 28; value += 0.25) {
210+
WinUHidPS4SetGyroState(&report, 0, value, 0);
211+
ASSERT_EQ(WinUHidPS4ReportInput(gamepad, &report), TRUE);
212+
213+
float expected[3] = { 0, value, 0 };
214+
gm.ExpectSensorData(SDL_SENSOR_GYRO, expected);
215+
}
216+
217+
for (float value = -28; value <= 28; value += 0.25) {
218+
WinUHidPS4SetGyroState(&report, 0, 0, value);
219+
ASSERT_EQ(WinUHidPS4ReportInput(gamepad, &report), TRUE);
220+
221+
float expected[3] = { 0, 0, value };
222+
gm.ExpectSensorData(SDL_SENSOR_GYRO, expected);
223+
}
224+
225+
for (float value = -32; value <= 32; value += 0.25) {
226+
WinUHidPS4SetAccelState(&report, value, 0, 0);
227+
ASSERT_EQ(WinUHidPS4ReportInput(gamepad, &report), TRUE);
228+
229+
float expected[3] = { value, 0, 0 };
230+
gm.ExpectSensorData(SDL_SENSOR_ACCEL, expected);
231+
}
232+
233+
for (float value = -32; value <= 32; value += 0.25) {
234+
WinUHidPS4SetAccelState(&report, 0, value, 0);
235+
ASSERT_EQ(WinUHidPS4ReportInput(gamepad, &report), TRUE);
236+
237+
float expected[3] = { 0, value, 0 };
238+
gm.ExpectSensorData(SDL_SENSOR_ACCEL, expected);
239+
}
240+
241+
for (float value = -32; value <= 32; value += 0.25) {
242+
WinUHidPS4SetAccelState(&report, 0, 0, value);
243+
ASSERT_EQ(WinUHidPS4ReportInput(gamepad, &report), TRUE);
244+
245+
float expected[3] = { 0, 0, value };
246+
gm.ExpectSensorData(SDL_SENSOR_ACCEL, expected);
247+
}
248+
249+
WinUHidPS4Destroy(gamepad);
250+
}
251+
185252
//
186253
// The touchpad is 943 points wide, but SDL treats it as 920. Since we want to
187254
// validate against SDL's representation, we must also use 920 as the width.

WinUHidUnitTests/Utilities.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,24 @@ void SDLGamepadManager::ExpectTouchpadFingerState(int Finger, bool Down, float T
144144
EXPECT_FLOAT_EQ(actualX, TouchX) << "Finger " << Finger << " has unexpected X coordinate";
145145
EXPECT_FLOAT_EQ(actualY, TouchY) << "Finger " << Finger << " has unexpected Y coordinate";
146146
}
147+
}
148+
149+
void SDLGamepadManager::ExpectSensorData(SDL_SensorType sensor, float* values) {
150+
for (int i = 0; i < 100; i++) {
151+
float actualValues[3];
152+
EXPECT_TRUE(SDL_GetGamepadSensorData(GetGamepad(0), sensor, actualValues, ARRAYSIZE(actualValues)));
153+
154+
if (std::fabs(actualValues[0] - values[0]) < 0.01 &&
155+
std::fabs(actualValues[1] - values[1]) < 0.01 &&
156+
std::fabs(actualValues[2] - values[2]) < 0.01) {
157+
break;
158+
}
159+
SDL_Delay(1);
160+
}
161+
162+
float actualValues[3];
163+
EXPECT_TRUE(SDL_GetGamepadSensorData(GetGamepad(0), sensor, actualValues, ARRAYSIZE(actualValues)));
164+
ASSERT_NEAR(actualValues[0], values[0], 0.01) << "Sensor " << sensor << "has unexpected X coordinate";
165+
ASSERT_NEAR(actualValues[1], values[1], 0.01) << "Sensor " << sensor << "has unexpected Y coordinate";
166+
ASSERT_NEAR(actualValues[2], values[2], 0.01) << "Sensor " << sensor << "has unexpected Z coordinate";
147167
}

WinUHidUnitTests/Utilities.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class SDLGamepadManager
2222
void ExpectHatState(int HatX, int HatY);
2323
void ExpectAxisValue(SDL_GamepadAxis Axis, Sint16 Value);
2424
void ExpectTouchpadFingerState(int Finger, bool Down, float TouchX, float TouchY);
25+
void ExpectSensorData(SDL_SensorType sensor, float* values);
2526

2627
private:
2728
static int EventPollThread(void* ptr);

0 commit comments

Comments
 (0)