Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,68 @@ int main(int argc, char** argv){
}
```

## Usage of Structs for Output State Configuration

The DS5 output state configuration relies on several structs to control features such as rumble effects. When preparing the output state, you set individual struct fields to adjust controller feedback and capabilities.

### Example: Configuring Rumble
```
outState.rumble.Mode = static_cast<unsigned char>(DS5W::RumbleMode::DefaultRumble);
outState.rumble.Feature = static_cast<unsigned char>(DS5W::FeatureMode::Advanced);

// Maximum is 0x15 (hex) = 21 (decimal)
outState.rumble.SoftRumbleReduce = 18;
```
### Description

- **Mode: `AdvancedRumble`**
Set the `Mode` field using `DS5W::RumbleMode::AdvancedRumble` to activate advanced rumble behavior, which enables finer feedback control and integration with audio or other dynamic sources.

- **Feature: `Advanced`**
Set the `Feature` field to `DS5W::FeatureMode::Advanced` to utilize extended feature sets provided by the controller, such as more complex vibration profiles based on audio cues.

### Description of Fields

- **Mode:**
Controls which audio output(s) are active.
- `AudioMode::Headset` – Output to the headset only
- `AudioMode::Speaker` – Output to the speaker only
- `AudioMode::HeadsetAndSpeaker` – Output to both headset and speaker

- **HeadsetVolume:**
Sets the volume level for the headset output. The decimal range is typically `0` (min) to `124` (max).

- **SpeakerVolume:**
Sets the volume level for the built-in speaker. The decimal range is typically `0` (min) to `124` (max).

- **MicVolume:**
Defines the microphone volume. Higher decimal values represent higher sensitivity or input levels, with `124` being maximum.

- **MicStatus:**
Controls the microphone state.
- `MicMode::On` – Microphone is enabled
- `MicMode::Mute` – Microphone is muted

### Typical Usage Scenarios

- Enable both headset and speaker output with maximum volumes and microphone muted:
```cpp
outState.audio.Mode = static_cast<unsigned char>(AudioMode::HeadsetAndSpeaker);
outState.audio.HeadsetVolume = 100;
outState.audio.SpeakerVolume = 100;
outState.audio.MicVolume = 100;
outState.audio.MicStatus = static_cast<unsigned char>(MicMode::Mute);
```

- Use only the headset output with microphone enabled:
```cpp
outState.audio.Mode = static_cast<unsigned char>(AudioMode::Headset);
outState.audio.HeadsetVolume = 100;
outState.audio.MicStatus = static_cast<unsigned char>(MicMode::On);
```

Adjust these settings according to your application's requirements to provide optimal audio feedback through the controller.

## Known issues

- When the controller being shut down while connected via Bluetooth (Holding the PS button). The lib will encounter a dead lock within `getDeviceInputState(...)` call. The function will return as soon as the controller is getting reconnected. Not encountering over USB, over USB the expected `DS5W_E_DEVICE_REMOVED` error is returned.
Expand Down
13 changes: 13 additions & 0 deletions VS19_Solution/.idea/.idea.VS19_Solution/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions VS19_Solution/.idea/.idea.VS19_Solution/.idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions VS19_Solution/.idea/.idea.VS19_Solution/.idea/indexLayout.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions VS19_Solution/.idea/.idea.VS19_Solution/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions VS19_Solution/DS5W_Test/src/wWinMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <DualSenseWindows/IO.h>
#include <DualSenseWindows/Device.h>
#include <DualSenseWindows/Helpers.h>
#include <iostream>

typedef std::wstringstream wstrBuilder;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
https://github.com/Ohjurot/DualSense-Windows

Contributors of this file:
11.2020 Ludwig F�chsl
11.2020 Ludwig Füchsl

Licensed under the MIT License (To be found in repository root directory)
*/
#pragma once

// Function Buttons DualSense Edge
#define DS5W_ISTATE_BTN_FN1 0x10
#define DS5W_ISTATE_BTN_FN2 0x20
#define DS5W_ISTATE_BTN_PADDLE_LEFT 0x40
#define DS5W_ISTATE_BTN_PADDLE_RIGHT 0x80

#define DS5W_ISTATE_BTX_SQUARE 0x10
#define DS5W_ISTATE_BTX_CROSS 0x20
#define DS5W_ISTATE_BTX_CIRCLE 0x40
Expand Down Expand Up @@ -71,7 +77,71 @@ namespace DS5W {
unsigned char g;
unsigned char b;
} Color;

typedef enum class _AudioMode : unsigned char{
/// <summary>
/// Enable Audio Headset
/// </summary>
Headset = 0x05,

/// <summary>
/// Enable Audio Speaker
/// </summary>
Speaker = 0x31,

/// <summary>
/// Enable Audio Headset And Speaker
/// </summary>
HeadsetAndSpeaker = 0x21,
} AudioMode;

typedef enum class _MicMode : unsigned char{
/// <summary>
/// Enable Audio Speaker
/// </summary>
On = 0x00,

/// <summary>
/// Mute Mic
/// </summary>
Mute = 0x10,
} MicMode;

/// <summary>
/// Audio Settings
/// </summary>
typedef struct _AudioConfig {
unsigned char Mode = static_cast<unsigned char>(AudioMode::Speaker);
unsigned char HeadsetVolume = 0x7C;
unsigned char SpeakerVolume = 0x7C;
unsigned char MicVolume = 0x7C;
unsigned char MicStatus = static_cast<unsigned char>(MicMode::On);
} AudioConfig;

/// <summary>
/// Rumble Mode
/// </summary>
typedef enum class _RumbleMode : unsigned char{
/// <summary>
/// Default Rumble
/// </summary>
DefaultRumble = 0xFF,

/// <summary>
/// Soft Rumble
/// </summary>
AdvancedRumble = 0xFC,
} RumbleMode;

/// <summary>
/// Rumble Settings
/// </summary>
typedef struct _RumbleConfig {
unsigned char Mode = static_cast<unsigned char>(RumbleMode::DefaultRumble);
unsigned char SoftRumbleReduce = 0x00;
unsigned char TriggerSoftnessLevel = 0x00;
} RumbleConfig;

/// <summary>
/// Touchpad state
/// </summary>
Expand Down Expand Up @@ -380,6 +450,11 @@ namespace DS5W {
} DS5InputState;

typedef struct _DS5OutputState {
/// <summary>
/// Rumble Config
/// </summary>
RumbleConfig rumbleSettings;

/// <summary>
/// Left / Hard rumbel motor
/// </summary>
Expand All @@ -390,6 +465,11 @@ namespace DS5W {
/// </summary>
unsigned char rightRumble;

/// <summary>
/// Audio Config
/// </summary>
AudioConfig audio;

/// <summary>
/// State of the microphone led
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

MIT License

Copyright (c) 2020 Ludwig F�chsl
Copyright (c) 2020 Ludwig Füchsl

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ void __DS5W::Input::evaluateHidInputBuffer(unsigned char* hidInBuffer, DS5W::DS5
ptrInputState->buttonsAndDpad |= DS5W_ISTATE_DPAD_RIGHT | DS5W_ISTATE_DPAD_DOWN;
break;
}

// Copy accelerometer readings
memcpy(&ptrInputState->accelerometer, &hidInBuffer[0x0F], 2 * 3);

//TEMP: Copy gyro data (no processing currently done!)
memcpy(&ptrInputState->gyroscope, &hidInBuffer[0x15], 2 * 3);

ptrInputState->gyroscope.x = static_cast<short>((hidInBuffer[0x10]) | (hidInBuffer[0x11] << 8));
ptrInputState->gyroscope.y = static_cast<short>((hidInBuffer[0x12]) | (hidInBuffer[0x13] << 8));
ptrInputState->gyroscope.z = static_cast<short>((hidInBuffer[0x14]) | (hidInBuffer[0x15] << 8));

ptrInputState->accelerometer.x = static_cast<short>((hidInBuffer[0x16]) | (hidInBuffer[0x17] << 8));
ptrInputState->accelerometer.y = static_cast<short>((hidInBuffer[0x18]) | (hidInBuffer[0x19] << 8));
ptrInputState->accelerometer.z = static_cast<short>((hidInBuffer[0x1A]) | (hidInBuffer[0x1B] << 8));

// Evaluate touch state 1
UINT32 touchpad1Raw = *(UINT32*)(&hidInBuffer[0x20]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
https://github.com/Ohjurot/DualSense-Windows

Contributors of this file:
11.2020 Ludwig F�chsl
11.2020 Ludwig Füchsl

Licensed under the MIT License (To be found in repository root directory)
*/
Expand Down
26 changes: 22 additions & 4 deletions VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
#include "DS5_Output.h"

void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState) {
void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState, DS5W::DeviceConnection Connection) {
bool bIsBluetooth = false;
if (Connection == DS5W::DeviceConnection::BT)
{
bIsBluetooth = true;
}

// Feature mask
hidOutBuffer[0x00] = 0xFF;
hidOutBuffer[0x00] = ptrOutputState->rumbleSettings.Mode;
hidOutBuffer[0x01] = 0xF7;

// Rumbel motors
hidOutBuffer[0x02] = ptrOutputState->rightRumble;
hidOutBuffer[0x03] = ptrOutputState->leftRumble;

// Audio
if (!bIsBluetooth)
{
hidOutBuffer[0x04] = ptrOutputState->audio.HeadsetVolume;
hidOutBuffer[0x05] = ptrOutputState->audio.SpeakerVolume;
hidOutBuffer[0x06] = ptrOutputState->audio.MicVolume;
hidOutBuffer[0x07] = ptrOutputState->audio.Mode;
hidOutBuffer[0x09] = ptrOutputState->audio.MicStatus;
}
// Mic led
hidOutBuffer[0x08] = (unsigned char)ptrOutputState->microphoneLed;
hidOutBuffer[0x08] = static_cast<unsigned char>(ptrOutputState->microphoneLed);

// Advanced Trigger Softness Level and Vibration Soft Rumble Reduce
hidOutBuffer[0x24] = static_cast<unsigned char>((ptrOutputState->rumbleSettings.TriggerSoftnessLevel << 4) | (ptrOutputState->rumbleSettings.SoftRumbleReduce & 0x0F));
hidOutBuffer[0x26] = 0x04;

// Player led
hidOutBuffer[0x2B] = ptrOutputState->playerLeds.bitmask;
Expand All @@ -22,7 +41,6 @@ void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS
}

// Player led brightness
hidOutBuffer[0x26] = 0x03;
hidOutBuffer[0x29] = ptrOutputState->disableLeds ? 0x01 : 0x2;
hidOutBuffer[0x2A] = ptrOutputState->playerLeds.brightness;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
https://github.com/Ohjurot/DualSense-Windows

Contributors of this file:
11.2020 Ludwig F�chsl
11.2020 Ludwig Füchsl

Licensed under the MIT License (To be found in repository root directory)
*/
Expand All @@ -22,7 +22,7 @@ namespace __DS5W {
/// </summary>
/// <param name="hidOutBuffer">HID Output buffer</param>
/// <param name="ptrOutputState">Pointer to state to read from</param>
void createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState);
void createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState, DS5W::DeviceConnection Connection);

/// <summary>
/// Process trigger
Expand Down
14 changes: 7 additions & 7 deletions VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
https://github.com/Ohjurot/DualSense-Windows

Contributors of this file:
11.2020 Ludwig F�chsl
11.2020 Ludwig Füchsl

Licensed under the MIT License (To be found in repository root directory)
*/
Expand Down Expand Up @@ -88,7 +88,7 @@ DS5W_API DS5W_ReturnValue DS5W::enumDevices(void* ptrBuffer, unsigned int inArrL
}

// Check if ids match
if (vendorId == 0x054C && productId == 0x0CE6) {
if (vendorId == 0x054C && (productId == 0x0CE6 || productId == 0x0DF2)) {
// Get pointer to target
DS5W::DeviceEnumInfo* ptrInfo = nullptr;
if (inputArrIndex < inArrLength) {
Expand Down Expand Up @@ -322,12 +322,12 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon
// Get otuput report length
unsigned short outputReportLength = 0;
if (ptrContext->_internal.connection == DS5W::DeviceConnection::BT) {
// The bluetooth input report is 547 Bytes long
outputReportLength = 547;
// The bluetooth input report is 78 Bytes long
outputReportLength = 78;
}
else {
// The usb input report is 48 Bytes long
outputReportLength = 48;
outputReportLength = 74;
}

// Cleat all input data
Expand All @@ -339,7 +339,7 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon
// Report type
ptrContext->_internal.hidBuffer[0x00] = 0x31;
ptrContext->_internal.hidBuffer[0x01] = 0x02;
__DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[2], ptrOutputState);
__DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[2], ptrOutputState, ptrContext->_internal.connection);

// Hash
const UINT32 crcChecksum = __DS5W::CRC32::compute(ptrContext->_internal.hidBuffer, 74);
Expand All @@ -355,7 +355,7 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon
ptrContext->_internal.hidBuffer[0x00] = 0x02;

// Else it is USB so call its evaluator
__DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[1], ptrOutputState);
__DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[1], ptrOutputState, ptrContext->_internal.connection);
}

// Write to controller
Expand Down