/* Simple DirectMedia Layer Copyright (C) 2020 Valve Corporation This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef _CONTROLLER_STRUCTS_ #define _CONTROLLER_STRUCTS_ #pragma pack(1) // 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, // or just add fields to the end of existing payload structs which is expected to be // safe in all code consuming these as they should just consume/copy upto the prior size // they were aware of when processing. #define k_ValveInReportMsgVersion 0x01 typedef enum { ID_CONTROLLER_STATE = 1, ID_CONTROLLER_DEBUG = 2, ID_CONTROLLER_WIRELESS = 3, ID_CONTROLLER_STATUS = 4, ID_CONTROLLER_DEBUG2 = 5, ID_CONTROLLER_SECONDARY_STATE = 6, ID_CONTROLLER_BLE_STATE = 7, ID_CONTROLLER_MSG_COUNT } ValveInReportMessageIDs; typedef struct { unsigned short unReportVersion; unsigned char ucType; unsigned char ucLength; } ValveInReportHeader_t; // State payload typedef struct { // If packet num matches that on your prior call, then the controller state hasn't been changed since // your last call and there is no need to process it uint32 unPacketNum; // Button bitmask and trigger data. union { uint64 ulButtons; struct { unsigned char _pad0[3]; unsigned char nLeft; unsigned char nRight; unsigned char _pad1[3]; } Triggers; } ButtonTriggerData; // Left pad coordinates short sLeftPadX; short sLeftPadY; // Right pad coordinates short sRightPadX; short sRightPadY; // This is redundant, packed above, but still sent over wired unsigned short sTriggerL; unsigned short sTriggerR; // FIXME figure out a way to grab this stuff over wireless short sAccelX; short sAccelY; short sAccelZ; short sGyroX; short sGyroY; short sGyroZ; short sGyroQuatW; short sGyroQuatX; short sGyroQuatY; short sGyroQuatZ; } ValveControllerStatePacket_t; // BLE State payload this has to be re-formatted from the normal state because BLE controller shows up as //a HID device and we don't want to send all the optional parts of the message. Keep in sync with struct above. typedef struct { // If packet num matches that on your prior call, then the controller state hasn't been changed since // your last call and there is no need to process it uint32 unPacketNum; // Button bitmask and trigger data. union { uint64 ulButtons; struct { unsigned char _pad0[3]; unsigned char nLeft; unsigned char nRight; unsigned char _pad1[3]; } Triggers; } ButtonTriggerData; // Left pad coordinates short sLeftPadX; short sLeftPadY; // Right pad coordinates short sRightPadX; short sRightPadY; //This mimcs how the dongle reconstitutes HID packets, there will be 0-4 shorts depending on gyro mode unsigned char ucGyroDataType; //TODO could maybe find some unused bits in the button field for this info (is only 2bits) short sGyro[4]; } ValveControllerBLEStatePacket_t; // Define a payload for reporting debug information typedef struct { // Left pad coordinates short sLeftPadX; short sLeftPadY; // Right pad coordinates short sRightPadX; short sRightPadY; // Left mouse deltas short sLeftPadMouseDX; short sLeftPadMouseDY; // Right mouse deltas short sRightPadMouseDX; short sRightPadMouseDY; // Left mouse filtered deltas short sLeftPadMouseFilteredDX; short sLeftPadMouseFilteredDY; // Right mouse filtered deltas short sRightPadMouseFilteredDX; short sRightPadMouseFilteredDY; // Pad Z values unsigned char ucLeftZ; unsigned char ucRightZ; // FingerPresent unsigned char ucLeftFingerPresent; unsigned char ucRightFingerPresent; // Timestamps unsigned char ucLeftTimestamp; unsigned char ucRightTimestamp; // Double tap state unsigned char ucLeftTapState; unsigned char ucRightTapState; unsigned int unDigitalIOStates0; unsigned int unDigitalIOStates1; } ValveControllerDebugPacket_t; typedef struct { unsigned char ucPadNum; unsigned char ucPad[3]; // need Data to be word aligned short Data[20]; unsigned short unNoise; } ValveControllerTrackpadImage_t; typedef struct { unsigned char ucPadNum; unsigned char ucOffset; unsigned char ucPad[2]; // need Data to be word aligned short rgData[28]; } ValveControllerRawTrackpadImage_t; // Payload for wireless metadata typedef struct { unsigned char ucEventType; } SteamControllerWirelessEvent_t; typedef struct { // Current packet number. unsigned int unPacketNum; // Event codes and state information. unsigned short sEventCode; unsigned short unStateFlags; // Current battery voltage (mV). unsigned short sBatteryVoltage; // Current battery level (0-100). unsigned char ucBatteryLevel; } SteamControllerStatusEvent_t; typedef struct { ValveInReportHeader_t header; union { ValveControllerStatePacket_t controllerState; ValveControllerBLEStatePacket_t controllerBLEState; ValveControllerDebugPacket_t debugState; ValveControllerTrackpadImage_t padImage; ValveControllerRawTrackpadImage_t rawPadImage; SteamControllerWirelessEvent_t wirelessEvent; SteamControllerStatusEvent_t statusEvent; } payload; } ValveInReport_t; // Enumeration for BLE packet protocol enum EBLEPacketReportNums { // Skipping past 2-3 because they are escape characters in Uart protocol k_EBLEReportState = 4, k_EBLEReportStatus = 5, }; // Enumeration of data chunks in BLE state packets enum EBLEOptionDataChunksBitmask { // First byte uppper nibble k_EBLEButtonChunk1 = 0x10, k_EBLEButtonChunk2 = 0x20, k_EBLEButtonChunk3 = 0x40, k_EBLELeftJoystickChunk = 0x80, // Second full byte k_EBLELeftTrackpadChunk = 0x100, k_EBLERightTrackpadChunk = 0x200, k_EBLEIMUAccelChunk = 0x400, k_EBLEIMUGyroChunk = 0x800, k_EBLEIMUQuatChunk = 0x1000, }; #pragma pack() #endif // _CONTROLLER_STRUCTS