From ea1a2b94f2850766a19f7d6d7ad3af809a0274a2 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 2 Oct 2021 09:12:57 -0700
Subject: [PATCH] Use the correct update rate for Steam Controller sensors
---
src/joystick/hidapi/SDL_hidapi_steam.c | 46 ++++++++++++++++---
.../hidapi/steam/controller_structs.h | 37 +++++++++++++++
2 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c
index caa10510d0..b015e6ba22 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam.c
@@ -421,13 +421,15 @@ static int ReadResponse( hid_device *dev, uint8_t uBuffer[65], int nExpectedResp
//---------------------------------------------------------------------------
// Reset steam controller (unmap buttons and pads) and re-fetch capability bits
//---------------------------------------------------------------------------
-static bool ResetSteamController( hid_device *dev, bool bSuppressErrorSpew )
+static bool ResetSteamController( hid_device *dev, bool bSuppressErrorSpew, uint32_t *punUpdateRateUS )
{
// Firmware quirk: Set Feature and Get Feature requests always require a 65-byte buffer.
unsigned char buf[65];
- int res = -1;
+ int res = -1, i;
int nSettings = 0;
int nAttributesLength;
+ FeatureReportMsg *msg;
+ uint32_t unUpdateRateUS = 9000; // Good default rate
DPRINTF( "ResetSteamController hid=%p\n", dev );
@@ -459,7 +461,33 @@ static bool ResetSteamController( hid_device *dev, bool bSuppressErrorSpew )
printf( "Bad GET_ATTRIBUTES_VALUES response for controller %p\n", dev );
return false;
}
-
+
+ msg = (FeatureReportMsg *)&buf[1];
+ for ( i = 0; i < (int)msg->header.length / sizeof( ControllerAttribute ); ++i )
+ {
+ uint8_t unAttribute = msg->payload.getAttributes.attributes[i].attributeTag;
+ uint32_t unValue = msg->payload.getAttributes.attributes[i].attributeValue;
+
+ switch ( unAttribute )
+ {
+ case ATTRIB_UNIQUE_ID:
+ break;
+ case ATTRIB_PRODUCT_ID:
+ break;
+ case ATTRIB_CAPABILITIES:
+ break;
+ case ATTRIB_CONNECTION_INTERVAL_IN_US:
+ unUpdateRateUS = unValue;
+ break;
+ default:
+ break;
+ }
+ }
+ if ( punUpdateRateUS )
+ {
+ *punUpdateRateUS = unUpdateRateUS;
+ }
+
// Clear digital button mappings
buf[0] = 0;
buf[1] = ID_CLEAR_DIGITAL_MAPPINGS;
@@ -1002,6 +1030,8 @@ static SDL_bool
HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverSteam_Context *ctx;
+ uint32_t update_rate_in_us = 0;
+ float update_rate_in_hz = 0.0f;
ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
@@ -1017,9 +1047,13 @@ HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
}
hid_set_nonblocking(device->dev, 1);
- if (!ResetSteamController(device->dev, false)) {
+ if (!ResetSteamController(device->dev, false, &update_rate_in_us)) {
+ SDL_SetError("Couldn't reset controller");
goto error;
}
+ if (update_rate_in_us > 0) {
+ update_rate_in_hz = 1000000.0f / update_rate_in_us;
+ }
InitializeSteamControllerPacketAssembler(&ctx->m_assembler);
@@ -1027,8 +1061,8 @@ HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
joystick->nbuttons = 17;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
- SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f);
- SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f);
+ SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, update_rate_in_hz);
+ SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz);
return SDL_TRUE;
diff --git a/src/joystick/hidapi/steam/controller_structs.h b/src/joystick/hidapi/steam/controller_structs.h
index 967c96f40a..c8fd61226e 100644
--- a/src/joystick/hidapi/steam/controller_structs.h
+++ b/src/joystick/hidapi/steam/controller_structs.h
@@ -23,6 +23,43 @@
#pragma pack(1)
+#define HID_FEATURE_REPORT_BYTES 64
+
+// Header for all host <==> target messages
+typedef struct
+{
+ unsigned char type;
+ unsigned char length;
+} FeatureReportHeader;
+
+// Generic controller attribute structure
+typedef struct
+{
+ unsigned char attributeTag;
+ uint32_t attributeValue;
+} ControllerAttribute;
+
+// Generic controller settings structure
+typedef struct
+{
+ ControllerAttribute attributes[ ( HID_FEATURE_REPORT_BYTES - sizeof( FeatureReportHeader ) ) / sizeof( ControllerAttribute ) ];
+} MsgGetAttributes;
+
+
+// This is the only message struct that application code should use to interact with feature request messages. Any new
+// messages should be added to the union. The structures defined here should correspond to the ones defined in
+// ValveDeviceCore.cpp.
+//
+typedef struct
+{
+ FeatureReportHeader header;
+ union
+ {
+ MsgGetAttributes getAttributes;
+ } payload;
+
+} FeatureReportMsg;
+
// Roll this version forward anytime that you are breaking compatibility of existing
// message types within ValveInReport_t or the header itself. Hopefully this should
// be super rare and instead you shoudl just add new message payloads to the union,