Protocol extension: DualSense adaptive trigger support (#102)

This commit is contained in:
ABeltramo 2025-03-26 00:16:11 +01:00 committed by GitHub
parent d3d3e6cf01
commit e95feaf495
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 58 additions and 4 deletions

View File

@ -66,6 +66,22 @@ typedef struct _QUEUED_ASYNC_CALLBACK {
uint8_t g;
uint8_t b;
} setControllerLed;
struct {
uint16_t controllerNumber;
/**
* 0x04 - Right trigger
* 0x08 - Left trigger
*/
uint8_t eventFlags;
uint8_t typeLeft;
uint8_t typeRight;
// arrays of size DS_EFFECT_PAYLOAD_SIZE
// this is an opaque payload that will be read directly from the joypad and set as is to the client controller
// if you are curious about the actual data, there's some rationale in
// https://gist.github.com/Nielk1/6d54cc2c00d2201ccb8c2720ad7538db
uint8_t left[DS_EFFECT_PAYLOAD_SIZE];
uint8_t right[DS_EFFECT_PAYLOAD_SIZE];
} dsAdaptiveTrigger;
} data;
LINKED_BLOCKING_QUEUE_ENTRY entry;
} QUEUED_ASYNC_CALLBACK, *PQUEUED_ASYNC_CALLBACK;
@ -122,6 +138,7 @@ static PPLT_CRYPTO_CONTEXT decryptionCtx;
#define IDX_RUMBLE_TRIGGER_DATA 9
#define IDX_SET_MOTION_EVENT 10
#define IDX_SET_RGB_LED 11
#define IDX_DS_ADAPTIVE_TRIGGERS 12
#define CONTROL_STREAM_TIMEOUT_SEC 10
#define CONTROL_STREAM_LINGER_TIMEOUT_SEC 2
@ -195,6 +212,7 @@ static const short packetTypesGen7Enc[] = {
0x5500, // Rumble triggers (Sunshine protocol extension)
0x5501, // Set motion event (Sunshine protocol extension)
0x5502, // Set RGB LED (Sunshine protocol extension)
0x5503, // Set Adaptive Triggers (Sunshine protocol extension)
};
static const char requestIdrFrameGen3[] = { 0, 0 };
@ -960,6 +978,14 @@ static void asyncCallbackThreadFunc(void* context) {
queuedCb->data.setMotionEventState.motionType,
queuedCb->data.setMotionEventState.reportRateHz);
break;
case IDX_DS_ADAPTIVE_TRIGGERS:
ListenerCallbacks.setAdaptiveTriggers(queuedCb->data.dsAdaptiveTrigger.controllerNumber,
queuedCb->data.dsAdaptiveTrigger.eventFlags,
queuedCb->data.dsAdaptiveTrigger.typeLeft,
queuedCb->data.dsAdaptiveTrigger.typeRight,
queuedCb->data.dsAdaptiveTrigger.left,
queuedCb->data.dsAdaptiveTrigger.right);
break;
default:
// Unhandled packet type from queueAsyncCallback()
LC_ASSERT(false);
@ -975,7 +1001,8 @@ static bool needsAsyncCallback(unsigned short packetType) {
packetType == packetTypes[IDX_RUMBLE_TRIGGER_DATA] ||
packetType == packetTypes[IDX_SET_MOTION_EVENT] ||
packetType == packetTypes[IDX_SET_RGB_LED] ||
packetType == packetTypes[IDX_HDR_INFO];
packetType == packetTypes[IDX_HDR_INFO] ||
packetType == packetTypes[IDX_DS_ADAPTIVE_TRIGGERS];
}
static void queueAsyncCallback(PNVCTL_ENET_PACKET_HEADER_V1 ctlHdr, int packetLength) {
@ -1026,6 +1053,20 @@ static void queueAsyncCallback(PNVCTL_ENET_PACKET_HEADER_V1 ctlHdr, int packetLe
else if (ctlHdr->type == packetTypes[IDX_HDR_INFO]) {
queuedCb->typeIndex = IDX_HDR_INFO;
}
else if (ctlHdr->type == packetTypes[IDX_DS_ADAPTIVE_TRIGGERS]){
BbGet16(&bb, &queuedCb->data.dsAdaptiveTrigger.controllerNumber);
BbGet8(&bb, &queuedCb->data.dsAdaptiveTrigger.eventFlags);
BbGet8(&bb, &queuedCb->data.dsAdaptiveTrigger.typeLeft);
BbGet8(&bb, &queuedCb->data.dsAdaptiveTrigger.typeRight);
for(int i = 0; i < DS_EFFECT_PAYLOAD_SIZE; i++) {
BbGet8(&bb, &queuedCb->data.dsAdaptiveTrigger.left[i]);
}
for(int i = 0; i < DS_EFFECT_PAYLOAD_SIZE; i++) {
BbGet8(&bb, &queuedCb->data.dsAdaptiveTrigger.right[i]);
}
queuedCb->typeIndex = IDX_DS_ADAPTIVE_TRIGGERS;
}
else {
// Unhandled packet type from needsAsyncCallback()
LC_ASSERT(false);

View File

@ -39,6 +39,7 @@ static void fakeClConnectionStatusUpdate(int connectionStatus) {}
static void fakeClSetHdrMode(bool enabled) {}
static void fakeClRumbleTriggers(uint16_t controllerNumber, uint16_t leftTriggerMotor, uint16_t rightTriggerMotor) {}
static void fakeClSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz) {}
static void fakeClSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlags, uint8_t typeLeft, uint8_t typeRight, uint8_t *left, uint8_t *right) {};
static void fakeClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t b) {}
static CONNECTION_LISTENER_CALLBACKS fakeClCallbacks = {
@ -54,6 +55,7 @@ static CONNECTION_LISTENER_CALLBACKS fakeClCallbacks = {
.rumbleTriggers = fakeClRumbleTriggers,
.setMotionEventState = fakeClSetMotionEventState,
.setControllerLED = fakeClSetControllerLED,
.setAdaptiveTriggers = fakeClSetAdaptiveTriggers,
};
void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS* drCallbacks, PAUDIO_RENDERER_CALLBACKS* arCallbacks,
@ -141,5 +143,8 @@ void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS* drCallbacks, PAUDIO_REND
if ((*clCallbacks)->setControllerLED == NULL) {
(*clCallbacks)->setControllerLED = fakeClSetControllerLED;
}
if ((*clCallbacks)->setAdaptiveTriggers == NULL) {
(*clCallbacks)->setAdaptiveTriggers = fakeClSetAdaptiveTriggers;
}
}
}

View File

@ -469,6 +469,13 @@ typedef void(*ConnListenerRumbleTriggers)(uint16_t controllerNumber, uint16_t le
// If reportRateHz is 0, the host is asking for motion event reporting to stop.
typedef void(*ConnListenerSetMotionEventState)(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz);
// This callback is invoked to notify the client of a change in the dualsense
// adaptive trigger configuration.
#define DS_EFFECT_PAYLOAD_SIZE 10
#define DS_EFFECT_RIGHT_TRIGGER 0x04
#define DS_EFFECT_LEFT_TRIGGER 0x08
typedef void(*ConnListenerSetAdaptiveTriggers)(uint16_t controllerNumber, uint8_t eventFlags, uint8_t typeLeft, uint8_t typeRight, uint8_t *left, uint8_t *right);
// This callback is invoked to set a controller's RGB LED (if present).
typedef void(*ConnListenerSetControllerLED)(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t b);
@ -485,6 +492,7 @@ typedef struct _CONNECTION_LISTENER_CALLBACKS {
ConnListenerRumbleTriggers rumbleTriggers;
ConnListenerSetMotionEventState setMotionEventState;
ConnListenerSetControllerLED setControllerLED;
ConnListenerSetAdaptiveTriggers setAdaptiveTriggers;
} CONNECTION_LISTENER_CALLBACKS, *PCONNECTION_LISTENER_CALLBACKS;
// Use this function to zero the connection callbacks when allocated on the stack or heap