From ea1a2b94f2850766a19f7d6d7ad3af809a0274a2 Mon Sep 17 00:00:00 2001 From: Sam Lantinga 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 caa10510d..b015e6ba2 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 967c96f40..c8fd61226 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,