2020-12-13 21:50:41 +01:00
# include "stdafx.h"
2020-12-13 00:00:45 +01:00
# include "dualsense_pad_handler.h"
# include "Emu/Io/pad_config.h"
LOG_CHANNEL ( dualsense_log , " DualSense " ) ;
2021-02-13 01:25:39 +01:00
template < >
void fmt_class_string < DualSenseDevice : : DualSenseDataMode > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto mode )
{
switch ( mode )
{
case DualSenseDevice : : DualSenseDataMode : : Simple : return " Simple " ;
case DualSenseDevice : : DualSenseDataMode : : Enhanced : return " Enhanced " ;
}
return unknown ;
} ) ;
}
2020-12-13 00:00:45 +01:00
namespace
{
2021-02-11 23:27:33 +01:00
constexpr u32 DUALSENSE_ACC_RES_PER_G = 8192 ;
constexpr u32 DUALSENSE_GYRO_RES_PER_DEG_S = 1024 ;
constexpr u32 DUALSENSE_CALIBRATION_REPORT_SIZE = 41 ;
2021-10-15 00:12:15 +02:00
constexpr u32 DUALSENSE_VERSION_REPORT_SIZE = 64 ;
2021-02-11 23:27:33 +01:00
constexpr u32 DUALSENSE_BLUETOOTH_REPORT_SIZE = 78 ;
constexpr u32 DUALSENSE_USB_REPORT_SIZE = 63 ;
constexpr u32 DUALSENSE_COMMON_REPORT_SIZE = 47 ;
constexpr u32 DUALSENSE_INPUT_REPORT_GYRO_X_OFFSET = 15 ;
2021-03-30 10:58:11 +02:00
constexpr id_pair SONY_DUALSENSE_ID_0 = { 0x054C , 0x0CE6 } ;
2021-02-04 22:05:12 +01:00
2021-02-09 00:31:07 +01:00
enum
{
2021-02-09 01:02:59 +01:00
VALID_FLAG_0_COMPATIBLE_VIBRATION = 0x01 ,
VALID_FLAG_0_HAPTICS_SELECT = 0x02 ,
VALID_FLAG_1_MIC_MUTE_LED_CONTROL_ENABLE = 0x01 ,
VALID_FLAG_1_POWER_SAVE_CONTROL_ENABLE = 0x02 ,
VALID_FLAG_1_LIGHTBAR_CONTROL_ENABLE = 0x04 ,
VALID_FLAG_1_RELEASE_LEDS = 0x08 ,
VALID_FLAG_1_PLAYER_INDICATOR_CONTROL_ENABLE = 0x10 ,
VALID_FLAG_2_LIGHTBAR_SETUP_CONTROL_ENABLE = 0x02 ,
POWER_SAVE_CONTROL_MIC_MUTE = 0x10 ,
2021-03-05 22:08:13 +01:00
LIGHTBAR_SETUP_LIGHT_ON = 0x01 ,
2021-02-09 01:02:59 +01:00
LIGHTBAR_SETUP_LIGHT_OUT = 0x02 ,
2021-02-09 00:31:07 +01:00
} ;
2021-02-08 23:58:24 +01:00
struct output_report_common
{
u8 valid_flag_0 ;
u8 valid_flag_1 ;
u8 motor_right ;
u8 motor_left ;
u8 reserved [ 4 ] ;
u8 mute_button_led ;
u8 power_save_control ;
u8 reserved_2 [ 28 ] ;
u8 valid_flag_2 ;
u8 reserved_3 [ 2 ] ;
u8 lightbar_setup ;
u8 led_brightness ;
u8 player_leds ;
u8 lightbar_r ;
u8 lightbar_g ;
u8 lightbar_b ;
} ;
struct output_report_bt
{
u8 report_id ; // 0x31
u8 seq_tag ;
u8 tag ;
output_report_common common ;
u8 reserved [ 24 ] ;
u8 crc32 [ 4 ] ;
} ;
struct output_report_usb
{
u8 report_id ; // 0x02
output_report_common common ;
u8 reserved [ 15 ] ;
} ;
static_assert ( sizeof ( struct output_report_common ) = = DUALSENSE_COMMON_REPORT_SIZE ) ;
static_assert ( sizeof ( struct output_report_bt ) = = DUALSENSE_BLUETOOTH_REPORT_SIZE ) ;
static_assert ( sizeof ( struct output_report_usb ) = = DUALSENSE_USB_REPORT_SIZE ) ;
2020-12-13 00:00:45 +01:00
}
dualsense_pad_handler : : dualsense_pad_handler ( )
2021-03-30 10:58:11 +02:00
: hid_pad_handler < DualSenseDevice > ( pad_handler : : dualsense , { SONY_DUALSENSE_ID_0 } )
2020-12-13 00:00:45 +01:00
{
// Unique names for the config files and our pad settings dialog
button_list =
{
2021-08-08 16:45:45 +02:00
{ DualSenseKeyCodes : : None , " " } ,
2020-12-13 00:00:45 +01:00
{ DualSenseKeyCodes : : Triangle , " Triangle " } ,
{ DualSenseKeyCodes : : Circle , " Circle " } ,
{ DualSenseKeyCodes : : Cross , " Cross " } ,
{ DualSenseKeyCodes : : Square , " Square " } ,
{ DualSenseKeyCodes : : Left , " Left " } ,
{ DualSenseKeyCodes : : Right , " Right " } ,
{ DualSenseKeyCodes : : Up , " Up " } ,
{ DualSenseKeyCodes : : Down , " Down " } ,
{ DualSenseKeyCodes : : R1 , " R1 " } ,
{ DualSenseKeyCodes : : R2 , " R2 " } ,
{ DualSenseKeyCodes : : R3 , " R3 " } ,
{ DualSenseKeyCodes : : Options , " Options " } ,
{ DualSenseKeyCodes : : Share , " Share " } ,
{ DualSenseKeyCodes : : PSButton , " PS Button " } ,
2021-02-08 21:07:27 +01:00
{ DualSenseKeyCodes : : Mic , " Mic " } ,
2020-12-13 00:00:45 +01:00
{ DualSenseKeyCodes : : TouchPad , " Touch Pad " } ,
{ DualSenseKeyCodes : : L1 , " L1 " } ,
{ DualSenseKeyCodes : : L2 , " L2 " } ,
{ DualSenseKeyCodes : : L3 , " L3 " } ,
{ DualSenseKeyCodes : : LSXNeg , " LS X- " } ,
{ DualSenseKeyCodes : : LSXPos , " LS X+ " } ,
{ DualSenseKeyCodes : : LSYPos , " LS Y+ " } ,
{ DualSenseKeyCodes : : LSYNeg , " LS Y- " } ,
{ DualSenseKeyCodes : : RSXNeg , " RS X- " } ,
{ DualSenseKeyCodes : : RSXPos , " RS X+ " } ,
{ DualSenseKeyCodes : : RSYPos , " RS Y+ " } ,
{ DualSenseKeyCodes : : RSYNeg , " RS Y- " }
} ;
init_configs ( ) ;
// Define border values
thumb_max = 255 ;
trigger_min = 0 ;
trigger_max = 255 ;
vibration_min = 0 ;
vibration_max = 255 ;
// Set capabilities
b_has_config = true ;
b_has_rumble = true ;
b_has_deadzones = true ;
2021-02-09 00:31:07 +01:00
b_has_led = true ;
2021-02-28 04:50:23 +01:00
b_has_rgb = true ;
2021-03-03 00:33:10 +01:00
b_has_battery = true ;
2020-12-13 00:00:45 +01:00
m_name_string = " DualSense Pad # " ;
m_max_devices = CELL_PAD_MAX_PORT_NUM ;
m_trigger_threshold = trigger_max / 2 ;
m_thumb_threshold = thumb_max / 2 ;
}
2021-02-11 23:27:33 +01:00
void dualsense_pad_handler : : check_add_device ( hid_device * hidDevice , std : : string_view path , std : : wstring_view wide_serial )
2020-12-13 00:00:45 +01:00
{
2021-02-11 23:27:33 +01:00
if ( ! hidDevice )
{
return ;
}
DualSenseDevice * device = nullptr ;
for ( auto & controller : m_controllers )
{
ensure ( controller . second ) ;
if ( ! controller . second - > hidDevice )
{
device = controller . second . get ( ) ;
break ;
}
}
if ( ! device )
{
return ;
}
2020-12-13 00:00:45 +01:00
std : : string serial ;
2021-03-05 19:14:50 +01:00
std : : array < u8 , 65 > buf { } ;
2020-12-13 00:00:45 +01:00
buf [ 0 ] = 0x09 ;
// This will give us the bluetooth mac address of the device, regardless if we are on wired or bluetooth.
// So we can't use this to determine if it is a bluetooth device or not.
// Will also enable enhanced feature reports for bluetooth.
2021-10-01 01:47:14 +02:00
int res = hid_get_feature_report ( hidDevice , buf . data ( ) , 64 ) ;
if ( res < 0 )
{
dualsense_log . error ( " check_add_device: hid_get_feature_report 0x09 failed! result=%d, error=%s " , res , hid_error ( hidDevice ) ) ;
return ;
}
if ( res = = 21 )
2020-12-13 00:00:45 +01:00
{
serial = fmt : : format ( " %x%x%x%x%x%x " , buf [ 6 ] , buf [ 5 ] , buf [ 4 ] , buf [ 3 ] , buf [ 2 ] , buf [ 1 ] ) ;
2021-02-13 01:25:39 +01:00
device - > data_mode = DualSenseDevice : : DualSenseDataMode : : Enhanced ;
2020-12-13 00:00:45 +01:00
}
else
{
// We're probably on Bluetooth in this case, but for whatever reason the feature report failed.
// This will give us a less capable fallback.
2021-10-01 01:47:14 +02:00
dualsense_log . warning ( " check_add_device: hid_get_feature_report returned wrong size! Falling back to simple mode. (result=%d) " , res ) ;
2021-02-13 01:25:39 +01:00
device - > data_mode = DualSenseDevice : : DualSenseDataMode : : Simple ;
2021-02-11 23:27:33 +01:00
for ( wchar_t ch : wide_serial )
2020-12-13 00:00:45 +01:00
serial + = static_cast < uchar > ( ch ) ;
}
2021-02-11 23:27:33 +01:00
device - > hidDevice = hidDevice ;
if ( ! get_calibration_data ( device ) )
2021-02-04 22:05:12 +01:00
{
2021-02-11 23:27:33 +01:00
dualsense_log . error ( " check_add_device: get_calibration_data failed! " ) ;
2021-02-04 22:05:12 +01:00
hid_close ( hidDevice ) ;
2021-02-11 23:27:33 +01:00
device - > hidDevice = nullptr ;
2021-02-04 22:05:12 +01:00
return ;
}
2021-03-05 19:14:50 +01:00
u32 hw_version { } ;
u32 fw_version { } ;
buf [ 0 ] = 0x20 ;
2021-10-01 01:47:14 +02:00
2021-10-15 00:12:15 +02:00
res = hid_get_feature_report ( hidDevice , buf . data ( ) , DUALSENSE_VERSION_REPORT_SIZE ) ;
2021-10-01 01:47:14 +02:00
if ( res = = 65 )
2021-03-05 19:14:50 +01:00
{
hw_version = read_u32 ( & buf [ 24 ] ) ;
fw_version = read_u32 ( & buf [ 28 ] ) ;
}
else
{
2021-10-01 01:47:14 +02:00
dualsense_log . error ( " check_add_device: hid_get_feature_report 0x20 failed! Could not retrieve firmware version! result=%d, error=%s " , res , hid_error ( hidDevice ) ) ;
2021-03-05 19:14:50 +01:00
}
2020-12-13 00:00:45 +01:00
if ( hid_set_nonblocking ( hidDevice , 1 ) = = - 1 )
{
2021-02-11 23:27:33 +01:00
dualsense_log . error ( " check_add_device: hid_set_nonblocking failed! Reason: %s " , hid_error ( hidDevice ) ) ;
2020-12-13 00:00:45 +01:00
hid_close ( hidDevice ) ;
2021-02-11 23:27:33 +01:00
device - > hidDevice = nullptr ;
2020-12-13 00:00:45 +01:00
return ;
}
2021-02-11 23:27:33 +01:00
device - > has_calib_data = true ;
device - > path = path ;
2020-12-13 00:00:45 +01:00
2021-02-13 01:25:39 +01:00
// Activate
2021-02-11 23:27:33 +01:00
send_output_report ( device ) ;
2021-02-13 01:25:39 +01:00
// Get bluetooth information
get_data ( device ) ;
2021-03-05 19:14:50 +01:00
dualsense_log . notice ( " Added device: bluetooth=%d, data_mode=%s, serial='%s', hw_version: 0x%x, fw_version: 0x%x, path='%s' " , device - > bt_controller , device - > data_mode , serial , hw_version , fw_version , device - > path ) ;
2020-12-13 00:00:45 +01:00
}
2021-08-10 21:45:26 +02:00
void dualsense_pad_handler : : init_config ( cfg_pad * cfg )
2020-12-13 00:00:45 +01:00
{
if ( ! cfg ) return ;
// Set default button mapping
cfg - > ls_left . def = button_list . at ( DualSenseKeyCodes : : LSXNeg ) ;
cfg - > ls_down . def = button_list . at ( DualSenseKeyCodes : : LSYNeg ) ;
cfg - > ls_right . def = button_list . at ( DualSenseKeyCodes : : LSXPos ) ;
cfg - > ls_up . def = button_list . at ( DualSenseKeyCodes : : LSYPos ) ;
cfg - > rs_left . def = button_list . at ( DualSenseKeyCodes : : RSXNeg ) ;
cfg - > rs_down . def = button_list . at ( DualSenseKeyCodes : : RSYNeg ) ;
cfg - > rs_right . def = button_list . at ( DualSenseKeyCodes : : RSXPos ) ;
cfg - > rs_up . def = button_list . at ( DualSenseKeyCodes : : RSYPos ) ;
cfg - > start . def = button_list . at ( DualSenseKeyCodes : : Options ) ;
cfg - > select . def = button_list . at ( DualSenseKeyCodes : : Share ) ;
cfg - > ps . def = button_list . at ( DualSenseKeyCodes : : PSButton ) ;
cfg - > square . def = button_list . at ( DualSenseKeyCodes : : Square ) ;
cfg - > cross . def = button_list . at ( DualSenseKeyCodes : : Cross ) ;
cfg - > circle . def = button_list . at ( DualSenseKeyCodes : : Circle ) ;
cfg - > triangle . def = button_list . at ( DualSenseKeyCodes : : Triangle ) ;
cfg - > left . def = button_list . at ( DualSenseKeyCodes : : Left ) ;
cfg - > down . def = button_list . at ( DualSenseKeyCodes : : Down ) ;
cfg - > right . def = button_list . at ( DualSenseKeyCodes : : Right ) ;
cfg - > up . def = button_list . at ( DualSenseKeyCodes : : Up ) ;
cfg - > r1 . def = button_list . at ( DualSenseKeyCodes : : R1 ) ;
cfg - > r2 . def = button_list . at ( DualSenseKeyCodes : : R2 ) ;
cfg - > r3 . def = button_list . at ( DualSenseKeyCodes : : R3 ) ;
cfg - > l1 . def = button_list . at ( DualSenseKeyCodes : : L1 ) ;
cfg - > l2 . def = button_list . at ( DualSenseKeyCodes : : L2 ) ;
cfg - > l3 . def = button_list . at ( DualSenseKeyCodes : : L3 ) ;
2021-08-08 16:45:45 +02:00
cfg - > pressure_intensity_button . def = button_list . at ( DualSenseKeyCodes : : None ) ;
2021-08-06 02:08:18 +02:00
2020-12-13 00:00:45 +01:00
// Set default misc variables
cfg - > lstickdeadzone . def = 40 ; // between 0 and 255
cfg - > rstickdeadzone . def = 40 ; // between 0 and 255
cfg - > ltriggerthreshold . def = 0 ; // between 0 and 255
cfg - > rtriggerthreshold . def = 0 ; // between 0 and 255
cfg - > lpadsquircling . def = 8000 ;
cfg - > rpadsquircling . def = 8000 ;
// Set default color value
cfg - > colorR . def = 0 ;
cfg - > colorG . def = 0 ;
cfg - > colorB . def = 20 ;
// Set default LED options
cfg - > led_battery_indicator . def = false ;
cfg - > led_battery_indicator_brightness . def = 10 ;
cfg - > led_low_battery_blink . def = true ;
// apply defaults
cfg - > from_default ( ) ;
}
2021-02-11 23:27:33 +01:00
dualsense_pad_handler : : DataStatus dualsense_pad_handler : : get_data ( DualSenseDevice * device )
2020-12-13 00:00:45 +01:00
{
if ( ! device )
2021-02-11 23:27:33 +01:00
return DataStatus : : ReadError ;
2020-12-13 00:00:45 +01:00
std : : array < u8 , 128 > buf { } ;
const int res = hid_read ( device - > hidDevice , buf . data ( ) , 128 ) ;
2020-12-18 08:39:54 +01:00
2020-12-13 00:00:45 +01:00
if ( res = = - 1 )
2021-02-04 22:05:12 +01:00
{
// looks like controller disconnected or read error
2021-02-11 23:27:33 +01:00
return DataStatus : : ReadError ;
2021-02-04 22:05:12 +01:00
}
2020-12-13 00:00:45 +01:00
if ( res = = 0 )
2021-02-11 23:27:33 +01:00
return DataStatus : : NoNewData ;
2020-12-13 00:00:45 +01:00
u8 offset = 0 ;
switch ( buf [ 0 ] )
{
case 0x01 :
2021-02-04 22:05:12 +01:00
{
2020-12-13 00:00:45 +01:00
if ( res = = DUALSENSE_BLUETOOTH_REPORT_SIZE )
{
2021-02-13 01:25:39 +01:00
device - > data_mode = DualSenseDevice : : DualSenseDataMode : : Simple ;
device - > bt_controller = true ;
2020-12-13 00:00:45 +01:00
offset = 1 ;
}
else
{
2021-02-13 01:25:39 +01:00
device - > data_mode = DualSenseDevice : : DualSenseDataMode : : Enhanced ;
device - > bt_controller = false ;
2020-12-18 08:39:54 +01:00
offset = 1 ;
2020-12-13 00:00:45 +01:00
}
break ;
2021-02-04 22:05:12 +01:00
}
2020-12-13 00:00:45 +01:00
case 0x31 :
{
2021-02-13 01:25:39 +01:00
device - > data_mode = DualSenseDevice : : DualSenseDataMode : : Enhanced ;
device - > bt_controller = true ;
2020-12-13 00:00:45 +01:00
offset = 2 ;
const u8 btHdr = 0xA1 ;
const u32 crcHdr = CRCPP : : CRC : : Calculate ( & btHdr , 1 , crcTable ) ;
const u32 crcCalc = CRCPP : : CRC : : Calculate ( buf . data ( ) , ( DUALSENSE_BLUETOOTH_REPORT_SIZE - 4 ) , crcTable , crcHdr ) ;
const u32 crcReported = read_u32 ( & buf [ DUALSENSE_BLUETOOTH_REPORT_SIZE - 4 ] ) ;
if ( crcCalc ! = crcReported )
{
dualsense_log . warning ( " Data packet CRC check failed, ignoring! Received 0x%x, Expected 0x%x " , crcReported , crcCalc ) ;
2021-02-11 23:27:33 +01:00
return DataStatus : : NoNewData ;
2020-12-13 00:00:45 +01:00
}
break ;
}
default :
2021-02-11 23:27:33 +01:00
return DataStatus : : NoNewData ;
2020-12-13 00:00:45 +01:00
}
2021-02-04 22:05:12 +01:00
if ( device - > has_calib_data )
{
int calib_offset = offset + DUALSENSE_INPUT_REPORT_GYRO_X_OFFSET ;
2021-02-11 23:27:33 +01:00
for ( int i = 0 ; i < CalibIndex : : COUNT ; + + i )
2021-02-04 22:05:12 +01:00
{
const s16 raw_value = read_s16 ( & buf [ calib_offset ] ) ;
const s16 cal_value = apply_calibration ( raw_value , device - > calib_data [ i ] ) ;
buf [ calib_offset + + ] = ( static_cast < u16 > ( cal_value ) > > 0 ) & 0xFF ;
buf [ calib_offset + + ] = ( static_cast < u16 > ( cal_value ) > > 8 ) & 0xFF ;
}
}
2021-03-03 00:33:10 +01:00
// For now let's only get battery info in enhanced mode
if ( device - > data_mode = = DualSenseDevice : : DualSenseDataMode : : Enhanced )
{
const u8 battery_state = buf [ offset + 52 ] ;
const u8 battery_value = battery_state & 0x0F ; // 10% per unit, starting with 0-9%. So 100% equals unit 10
const u8 charge_info = ( battery_state & 0xF0 ) > > 4 ;
switch ( charge_info )
{
case 0x0 :
2021-03-05 20:32:58 +01:00
device - > battery_level = battery_value ;
2021-03-03 00:33:10 +01:00
device - > cable_state = 0 ;
break ;
case 0x1 :
2021-03-05 20:32:58 +01:00
device - > battery_level = battery_value ;
2021-03-03 00:33:10 +01:00
device - > cable_state = 1 ;
break ;
case 0x2 :
2021-03-05 20:32:58 +01:00
device - > battery_level = 10 ;
2021-03-03 00:33:10 +01:00
device - > cable_state = 1 ;
break ;
default :
// We don't care about the other values. Just set battery to 0.
device - > battery_level = 0 ;
device - > cable_state = 0 ;
break ;
}
}
2020-12-13 00:00:45 +01:00
memcpy ( device - > padData . data ( ) , & buf [ offset ] , 64 ) ;
2021-02-11 23:27:33 +01:00
return DataStatus : : NewData ;
2020-12-13 00:00:45 +01:00
}
2021-04-07 23:05:18 +02:00
bool dualsense_pad_handler : : get_calibration_data ( DualSenseDevice * dualsense_device ) const
2021-02-04 22:05:12 +01:00
{
if ( ! dualsense_device | | ! dualsense_device - > hidDevice )
{
dualsense_log . error ( " get_calibration_data called with null device " ) ;
return false ;
}
std : : array < u8 , 64 > buf ;
2021-02-13 01:25:39 +01:00
if ( dualsense_device - > bt_controller )
2021-02-04 22:05:12 +01:00
{
for ( int tries = 0 ; tries < 3 ; + + tries )
{
buf [ 0 ] = 0x05 ;
2021-10-01 01:47:14 +02:00
if ( int res = hid_get_feature_report ( dualsense_device - > hidDevice , buf . data ( ) , DUALSENSE_CALIBRATION_REPORT_SIZE ) ; res < = 0 )
2021-02-04 22:05:12 +01:00
{
2021-10-01 01:47:14 +02:00
dualsense_log . error ( " get_calibration_data: hid_get_feature_report 0x05 for bluetooth controller failed! result=%d, error=%s " , res , hid_error ( dualsense_device - > hidDevice ) ) ;
2021-02-04 22:05:12 +01:00
return false ;
}
const u8 btHdr = 0xA3 ;
const u32 crcHdr = CRCPP : : CRC : : Calculate ( & btHdr , 1 , crcTable ) ;
const u32 crcCalc = CRCPP : : CRC : : Calculate ( buf . data ( ) , ( DUALSENSE_CALIBRATION_REPORT_SIZE - 4 ) , crcTable , crcHdr ) ;
const u32 crcReported = read_u32 ( & buf [ DUALSENSE_CALIBRATION_REPORT_SIZE - 4 ] ) ;
if ( crcCalc = = crcReported )
break ;
dualsense_log . warning ( " Calibration CRC check failed! Will retry up to 3 times. Received 0x%x, Expected 0x%x " , crcReported , crcCalc ) ;
if ( tries = = 2 )
{
dualsense_log . error ( " Calibration CRC check failed too many times! " ) ;
return false ;
}
}
}
else
{
buf [ 0 ] = 0x05 ;
2021-10-01 01:47:14 +02:00
if ( int res = hid_get_feature_report ( dualsense_device - > hidDevice , buf . data ( ) , DUALSENSE_CALIBRATION_REPORT_SIZE ) ; res < = 0 )
2021-02-04 22:05:12 +01:00
{
2021-10-01 01:47:14 +02:00
dualsense_log . error ( " get_calibration_data: hid_get_feature_report 0x05 for wired controller failed! result=%d, error=%s " , res , hid_error ( dualsense_device - > hidDevice ) ) ;
2021-02-04 22:05:12 +01:00
return false ;
}
}
2021-02-11 23:27:33 +01:00
dualsense_device - > calib_data [ CalibIndex : : PITCH ] . bias = read_s16 ( & buf [ 1 ] ) ;
dualsense_device - > calib_data [ CalibIndex : : YAW ] . bias = read_s16 ( & buf [ 3 ] ) ;
dualsense_device - > calib_data [ CalibIndex : : ROLL ] . bias = read_s16 ( & buf [ 5 ] ) ;
2021-02-04 22:05:12 +01:00
s16 pitch_plus , pitch_minus , roll_plus , roll_minus , yaw_plus , yaw_minus ;
// TODO: This was copied from DS4. Find out if it applies here.
// Check for calibration data format
// It's going to be either alternating +/- or +++---
if ( read_s16 ( & buf [ 9 ] ) < 0 & & read_s16 ( & buf [ 7 ] ) > 0 )
{
// Wired mode for OEM controllers
pitch_plus = read_s16 ( & buf [ 7 ] ) ;
pitch_minus = read_s16 ( & buf [ 9 ] ) ;
yaw_plus = read_s16 ( & buf [ 11 ] ) ;
yaw_minus = read_s16 ( & buf [ 13 ] ) ;
roll_plus = read_s16 ( & buf [ 15 ] ) ;
roll_minus = read_s16 ( & buf [ 17 ] ) ;
}
else
{
// Bluetooth mode and wired mode for some 3rd party controllers
pitch_plus = read_s16 ( & buf [ 7 ] ) ;
yaw_plus = read_s16 ( & buf [ 9 ] ) ;
roll_plus = read_s16 ( & buf [ 11 ] ) ;
pitch_minus = read_s16 ( & buf [ 13 ] ) ;
yaw_minus = read_s16 ( & buf [ 15 ] ) ;
roll_minus = read_s16 ( & buf [ 17 ] ) ;
}
// Confirm correctness. Need confirmation with dongle with no active controller
if ( pitch_plus < = 0 | | yaw_plus < = 0 | | roll_plus < = 0 | |
pitch_minus > = 0 | | yaw_minus > = 0 | | roll_minus > = 0 )
{
dualsense_log . error ( " get_calibration_data: calibration data check failed! pitch_plus=%d, pitch_minus=%d, roll_plus=%d, roll_minus=%d, yaw_plus=%d, yaw_minus=%d " ,
pitch_plus , pitch_minus , roll_plus , roll_minus , yaw_plus , yaw_minus ) ;
return false ;
}
const s32 gyro_speed_scale = read_s16 ( & buf [ 19 ] ) + read_s16 ( & buf [ 21 ] ) ;
2021-02-11 23:27:33 +01:00
dualsense_device - > calib_data [ CalibIndex : : PITCH ] . sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S ;
dualsense_device - > calib_data [ CalibIndex : : PITCH ] . sens_denom = pitch_plus - pitch_minus ;
2021-02-04 22:05:12 +01:00
2021-02-11 23:27:33 +01:00
dualsense_device - > calib_data [ CalibIndex : : YAW ] . sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S ;
dualsense_device - > calib_data [ CalibIndex : : YAW ] . sens_denom = yaw_plus - yaw_minus ;
2021-02-04 22:05:12 +01:00
2021-02-11 23:27:33 +01:00
dualsense_device - > calib_data [ CalibIndex : : ROLL ] . sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S ;
dualsense_device - > calib_data [ CalibIndex : : ROLL ] . sens_denom = roll_plus - roll_minus ;
2021-02-04 22:05:12 +01:00
const s16 accel_x_plus = read_s16 ( & buf [ 23 ] ) ;
const s16 accel_x_minus = read_s16 ( & buf [ 25 ] ) ;
const s16 accel_y_plus = read_s16 ( & buf [ 27 ] ) ;
const s16 accel_y_minus = read_s16 ( & buf [ 29 ] ) ;
const s16 accel_z_plus = read_s16 ( & buf [ 31 ] ) ;
const s16 accel_z_minus = read_s16 ( & buf [ 33 ] ) ;
const s32 accel_x_range = accel_x_plus - accel_x_minus ;
const s32 accel_y_range = accel_y_plus - accel_y_minus ;
const s32 accel_z_range = accel_z_plus - accel_z_minus ;
2021-02-11 23:27:33 +01:00
dualsense_device - > calib_data [ CalibIndex : : X ] . bias = accel_x_plus - accel_x_range / 2 ;
dualsense_device - > calib_data [ CalibIndex : : X ] . sens_numer = 2 * DUALSENSE_ACC_RES_PER_G ;
dualsense_device - > calib_data [ CalibIndex : : X ] . sens_denom = accel_x_range ;
2021-02-04 22:05:12 +01:00
2021-02-11 23:27:33 +01:00
dualsense_device - > calib_data [ CalibIndex : : Y ] . bias = accel_y_plus - accel_y_range / 2 ;
dualsense_device - > calib_data [ CalibIndex : : Y ] . sens_numer = 2 * DUALSENSE_ACC_RES_PER_G ;
dualsense_device - > calib_data [ CalibIndex : : Y ] . sens_denom = accel_y_range ;
2021-02-04 22:05:12 +01:00
2021-02-11 23:27:33 +01:00
dualsense_device - > calib_data [ CalibIndex : : Z ] . bias = accel_z_plus - accel_z_range / 2 ;
dualsense_device - > calib_data [ CalibIndex : : Z ] . sens_numer = 2 * DUALSENSE_ACC_RES_PER_G ;
dualsense_device - > calib_data [ CalibIndex : : Z ] . sens_denom = accel_z_range ;
2021-02-04 22:05:12 +01:00
// Make sure data 'looks' valid, dongle will report invalid calibration data with no controller connected
for ( const auto & data : dualsense_device - > calib_data )
{
if ( data . sens_denom = = 0 )
{
dualsense_log . error ( " get_calibration_data: Failure: sens_denom == 0 " ) ;
return false ;
}
}
return true ;
}
2020-12-13 00:00:45 +01:00
bool dualsense_pad_handler : : get_is_left_trigger ( u64 keyCode )
{
return keyCode = = DualSenseKeyCodes : : L2 ;
}
bool dualsense_pad_handler : : get_is_right_trigger ( u64 keyCode )
{
return keyCode = = DualSenseKeyCodes : : R2 ;
}
bool dualsense_pad_handler : : get_is_left_stick ( u64 keyCode )
{
switch ( keyCode )
{
case DualSenseKeyCodes : : LSXNeg :
case DualSenseKeyCodes : : LSXPos :
case DualSenseKeyCodes : : LSYPos :
case DualSenseKeyCodes : : LSYNeg :
return true ;
default :
return false ;
}
}
bool dualsense_pad_handler : : get_is_right_stick ( u64 keyCode )
{
switch ( keyCode )
{
case DualSenseKeyCodes : : RSXNeg :
case DualSenseKeyCodes : : RSXPos :
case DualSenseKeyCodes : : RSYPos :
case DualSenseKeyCodes : : RSYNeg :
return true ;
default :
return false ;
}
}
PadHandlerBase : : connection dualsense_pad_handler : : update_connection ( const std : : shared_ptr < PadDevice > & device )
{
2021-02-11 23:27:33 +01:00
DualSenseDevice * dualsense_dev = static_cast < DualSenseDevice * > ( device . get ( ) ) ;
if ( ! dualsense_dev | | dualsense_dev - > path . empty ( ) )
2020-12-13 00:00:45 +01:00
return connection : : disconnected ;
if ( dualsense_dev - > hidDevice = = nullptr )
{
// try to reconnect
hid_device * dev = hid_open_path ( dualsense_dev - > path . c_str ( ) ) ;
if ( dev )
{
if ( hid_set_nonblocking ( dev , 1 ) = = - 1 )
{
dualsense_log . error ( " Reconnecting Device %s: hid_set_nonblocking failed with error %s " , dualsense_dev - > path , hid_error ( dev ) ) ;
}
dualsense_dev - > hidDevice = dev ;
2021-02-04 22:05:12 +01:00
if ( ! dualsense_dev - > has_calib_data )
dualsense_dev - > has_calib_data = get_calibration_data ( dualsense_dev ) ;
2020-12-13 00:00:45 +01:00
}
else
{
// nope, not there
return connection : : disconnected ;
}
}
2021-02-11 23:27:33 +01:00
if ( get_data ( dualsense_dev ) = = DataStatus : : ReadError )
2020-12-13 00:00:45 +01:00
{
// this also can mean disconnected, either way deal with it on next loop and reconnect
hid_close ( dualsense_dev - > hidDevice ) ;
dualsense_dev - > hidDevice = nullptr ;
return connection : : no_data ;
}
return connection : : connected ;
}
2021-02-04 22:05:12 +01:00
void dualsense_pad_handler : : get_extended_info ( const std : : shared_ptr < PadDevice > & device , const std : : shared_ptr < Pad > & pad )
{
2021-02-11 23:27:33 +01:00
DualSenseDevice * dualsense_device = static_cast < DualSenseDevice * > ( device . get ( ) ) ;
2021-02-04 22:05:12 +01:00
if ( ! dualsense_device | | ! pad )
return ;
2021-03-01 09:24:30 +01:00
pad - > m_battery_level = dualsense_device - > battery_level ;
pad - > m_cable_state = dualsense_device - > cable_state ;
2021-02-04 22:05:12 +01:00
2021-03-02 23:24:05 +01:00
auto & buf = dualsense_device - > padData ;
2021-02-04 22:05:12 +01:00
// these values come already calibrated, all we need to do is convert to ds3 range
// gyroX is yaw, which is all that we need
f32 gyroX = static_cast < s16 > ( ( buf [ 16 ] < < 8 ) | buf [ 15 ] ) / static_cast < f32 > ( DUALSENSE_GYRO_RES_PER_DEG_S ) * - 1 ;
//const int gyroY = ((u16)(buf[18] << 8) | buf[17]) / 256;
//const int gyroZ = ((u16)(buf[20] << 8) | buf[19]) / 256;
// accel
f32 accelX = static_cast < s16 > ( ( buf [ 22 ] < < 8 ) | buf [ 21 ] ) / static_cast < f32 > ( DUALSENSE_ACC_RES_PER_G ) * - 1 ;
f32 accelY = static_cast < s16 > ( ( buf [ 24 ] < < 8 ) | buf [ 23 ] ) / static_cast < f32 > ( DUALSENSE_ACC_RES_PER_G ) * - 1 ;
f32 accelZ = static_cast < s16 > ( ( buf [ 26 ] < < 8 ) | buf [ 25 ] ) / static_cast < f32 > ( DUALSENSE_ACC_RES_PER_G ) * - 1 ;
// now just use formula from ds3
accelX = accelX * 113 + 512 ;
accelY = accelY * 113 + 512 ;
accelZ = accelZ * 113 + 512 ;
// convert to ds3
gyroX = gyroX * ( 123.f / 90.f ) + 512 ;
pad - > m_sensors [ 0 ] . m_value = Clamp0To1023 ( accelX ) ;
pad - > m_sensors [ 1 ] . m_value = Clamp0To1023 ( accelY ) ;
pad - > m_sensors [ 2 ] . m_value = Clamp0To1023 ( accelZ ) ;
pad - > m_sensors [ 3 ] . m_value = Clamp0To1023 ( gyroX ) ;
}
2020-12-13 00:00:45 +01:00
std : : unordered_map < u64 , u16 > dualsense_pad_handler : : get_button_values ( const std : : shared_ptr < PadDevice > & device )
{
std : : unordered_map < u64 , u16 > keyBuffer ;
2021-02-11 23:27:33 +01:00
DualSenseDevice * dualsense_dev = static_cast < DualSenseDevice * > ( device . get ( ) ) ;
2020-12-13 00:00:45 +01:00
if ( ! dualsense_dev )
return keyBuffer ;
auto buf = dualsense_dev - > padData ;
2021-02-13 01:25:39 +01:00
if ( dualsense_dev - > data_mode = = DualSenseDevice : : DualSenseDataMode : : Simple )
2020-12-13 00:00:45 +01:00
{
// Left Stick X Axis
keyBuffer [ DualSenseKeyCodes : : LSXNeg ] = Clamp0To255 ( ( 127.5f - buf [ 0 ] ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : LSXPos ] = Clamp0To255 ( ( buf [ 0 ] - 127.5f ) * 2.0f ) ;
// Left Stick Y Axis (Up is the negative for some reason)
keyBuffer [ DualSenseKeyCodes : : LSYNeg ] = Clamp0To255 ( ( buf [ 1 ] - 127.5f ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : LSYPos ] = Clamp0To255 ( ( 127.5f - buf [ 1 ] ) * 2.0f ) ;
// Right Stick X Axis
keyBuffer [ DualSenseKeyCodes : : RSXNeg ] = Clamp0To255 ( ( 127.5f - buf [ 2 ] ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : RSXPos ] = Clamp0To255 ( ( buf [ 2 ] - 127.5f ) * 2.0f ) ;
// Right Stick Y Axis (Up is the negative for some reason)
keyBuffer [ DualSenseKeyCodes : : RSYNeg ] = Clamp0To255 ( ( buf [ 3 ] - 127.5f ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : RSYPos ] = Clamp0To255 ( ( 127.5f - buf [ 3 ] ) * 2.0f ) ;
// bleh, dpad in buffer is stored in a different state
u8 data = buf [ 4 ] & 0xf ;
switch ( data )
{
case 0x08 : // none pressed
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x07 : // NW...left and up
keyBuffer [ DualSenseKeyCodes : : Up ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x06 : // W..left
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x05 : // SW..left down
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x04 : // S..down
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x03 : // SE..down and right
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 255 ;
break ;
case 0x02 : // E... right
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 255 ;
break ;
case 0x01 : // NE.. up right
keyBuffer [ DualSenseKeyCodes : : Up ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 255 ;
break ;
case 0x00 : // n.. up
keyBuffer [ DualSenseKeyCodes : : Up ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
default :
fmt : : throw_exception ( " dualsense dpad state encountered unexpected input " ) ;
}
data = buf [ 4 ] > > 4 ;
keyBuffer [ DualSenseKeyCodes : : Square ] = ( ( data & 0x01 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Cross ] = ( ( data & 0x02 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Circle ] = ( ( data & 0x04 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Triangle ] = ( ( data & 0x08 ) ! = 0 ) ? 255 : 0 ;
data = buf [ 5 ] ;
keyBuffer [ DualSenseKeyCodes : : L1 ] = ( ( data & 0x01 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : R1 ] = ( ( data & 0x02 ) ! = 0 ) ? 255 : 0 ;
2021-02-08 21:07:27 +01:00
//keyBuffer[DualSenseKeyCodes::L2] = ((data & 0x04) != 0) ? 255 : 0; // active when L2 is pressed
//keyBuffer[DualSenseKeyCodes::R2] = ((data & 0x08) != 0) ? 255 : 0; // active when R2 is pressed
2020-12-13 00:00:45 +01:00
keyBuffer [ DualSenseKeyCodes : : Share ] = ( ( data & 0x10 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Options ] = ( ( data & 0x20 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : L3 ] = ( ( data & 0x40 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : R3 ] = ( ( data & 0x80 ) ! = 0 ) ? 255 : 0 ;
2021-02-08 21:07:27 +01:00
data = buf [ 6 ] ;
2020-12-13 00:00:45 +01:00
keyBuffer [ DualSenseKeyCodes : : PSButton ] = ( ( data & 0x01 ) ! = 0 ) ? 255 : 0 ;
2020-12-18 08:39:54 +01:00
keyBuffer [ DualSenseKeyCodes : : TouchPad ] = ( ( data & 0x02 ) ! = 0 ) ? 255 : 0 ;
2021-02-08 21:07:27 +01:00
keyBuffer [ DualSenseKeyCodes : : Mic ] = ( ( data & 0x04 ) ! = 0 ) ? 255 : 0 ;
2020-12-13 00:00:45 +01:00
2021-03-02 23:24:05 +01:00
keyBuffer [ DualSenseKeyCodes : : L2 ] = buf [ 7 ] ;
keyBuffer [ DualSenseKeyCodes : : R2 ] = buf [ 8 ] ;
2020-12-13 00:00:45 +01:00
return keyBuffer ;
}
// Left Stick X Axis
keyBuffer [ DualSenseKeyCodes : : LSXNeg ] = Clamp0To255 ( ( 127.5f - buf [ 0 ] ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : LSXPos ] = Clamp0To255 ( ( buf [ 0 ] - 127.5f ) * 2.0f ) ;
// Left Stick Y Axis (Up is the negative for some reason)
keyBuffer [ DualSenseKeyCodes : : LSYNeg ] = Clamp0To255 ( ( buf [ 1 ] - 127.5f ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : LSYPos ] = Clamp0To255 ( ( 127.5f - buf [ 1 ] ) * 2.0f ) ;
// Right Stick X Axis
keyBuffer [ DualSenseKeyCodes : : RSXNeg ] = Clamp0To255 ( ( 127.5f - buf [ 2 ] ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : RSXPos ] = Clamp0To255 ( ( buf [ 2 ] - 127.5f ) * 2.0f ) ;
// Right Stick Y Axis (Up is the negative for some reason)
keyBuffer [ DualSenseKeyCodes : : RSYNeg ] = Clamp0To255 ( ( buf [ 3 ] - 127.5f ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : RSYPos ] = Clamp0To255 ( ( 127.5f - buf [ 3 ] ) * 2.0f ) ;
2021-03-02 23:24:05 +01:00
keyBuffer [ DualSenseKeyCodes : : L2 ] = buf [ 4 ] ;
keyBuffer [ DualSenseKeyCodes : : R2 ] = buf [ 5 ] ;
2020-12-13 00:00:45 +01:00
u8 data = buf [ 7 ] & 0xf ;
switch ( data )
{
case 0x08 : // none pressed
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x07 : // NW...left and up
keyBuffer [ DualSenseKeyCodes : : Up ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x06 : // W..left
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x05 : // SW..left down
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x04 : // S..down
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
case 0x03 : // SE..down and right
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 255 ;
break ;
case 0x02 : // E... right
keyBuffer [ DualSenseKeyCodes : : Up ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 255 ;
break ;
case 0x01 : // NE.. up right
keyBuffer [ DualSenseKeyCodes : : Up ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 255 ;
break ;
case 0x00 : // n.. up
keyBuffer [ DualSenseKeyCodes : : Up ] = 255 ;
keyBuffer [ DualSenseKeyCodes : : Down ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Left ] = 0 ;
keyBuffer [ DualSenseKeyCodes : : Right ] = 0 ;
break ;
default :
fmt : : throw_exception ( " dualsense dpad state encountered unexpected input " ) ;
}
data = buf [ 7 ] > > 4 ;
keyBuffer [ DualSenseKeyCodes : : Square ] = ( ( data & 0x01 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Cross ] = ( ( data & 0x02 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Circle ] = ( ( data & 0x04 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Triangle ] = ( ( data & 0x08 ) ! = 0 ) ? 255 : 0 ;
data = buf [ 8 ] ;
keyBuffer [ DualSenseKeyCodes : : L1 ] = ( ( data & 0x01 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : R1 ] = ( ( data & 0x02 ) ! = 0 ) ? 255 : 0 ;
2021-02-08 21:07:27 +01:00
//keyBuffer[DualSenseKeyCodes::L2] = ((data & 0x04) != 0) ? 255 : 0; // active when L2 is pressed
//keyBuffer[DualSenseKeyCodes::R2] = ((data & 0x08) != 0) ? 255 : 0; // active when R2 is pressed
2020-12-13 00:00:45 +01:00
keyBuffer [ DualSenseKeyCodes : : Share ] = ( ( data & 0x10 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : Options ] = ( ( data & 0x20 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : L3 ] = ( ( data & 0x40 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : R3 ] = ( ( data & 0x80 ) ! = 0 ) ? 255 : 0 ;
2021-02-08 21:07:27 +01:00
data = buf [ 9 ] ;
2020-12-13 00:00:45 +01:00
keyBuffer [ DualSenseKeyCodes : : PSButton ] = ( ( data & 0x01 ) ! = 0 ) ? 255 : 0 ;
2020-12-18 08:39:54 +01:00
keyBuffer [ DualSenseKeyCodes : : TouchPad ] = ( ( data & 0x02 ) ! = 0 ) ? 255 : 0 ;
2021-02-08 21:07:27 +01:00
keyBuffer [ DualSenseKeyCodes : : Mic ] = ( ( data & 0x04 ) ! = 0 ) ? 255 : 0 ;
2020-12-13 00:00:45 +01:00
return keyBuffer ;
}
2020-12-14 14:33:43 +01:00
pad_preview_values dualsense_pad_handler : : get_preview_values ( const std : : unordered_map < u64 , u16 > & data )
2020-12-13 00:00:45 +01:00
{
2020-12-14 14:33:43 +01:00
return {
data . at ( L2 ) ,
data . at ( R2 ) ,
data . at ( LSXPos ) - data . at ( LSXNeg ) ,
data . at ( LSYPos ) - data . at ( LSYNeg ) ,
data . at ( RSXPos ) - data . at ( RSXNeg ) ,
data . at ( RSYPos ) - data . at ( RSYNeg )
} ;
2020-12-13 00:00:45 +01:00
}
dualsense_pad_handler : : ~ dualsense_pad_handler ( )
{
2021-02-11 23:27:33 +01:00
for ( auto & controller : m_controllers )
2020-12-13 00:00:45 +01:00
{
2021-02-11 23:27:33 +01:00
if ( controller . second & & controller . second - > hidDevice )
2020-12-13 00:00:45 +01:00
{
// Disable vibration
2021-02-11 23:27:33 +01:00
controller . second - > small_motor = 0 ;
controller . second - > large_motor = 0 ;
send_output_report ( controller . second . get ( ) ) ;
2020-12-13 00:00:45 +01:00
}
}
}
2021-02-11 23:27:33 +01:00
int dualsense_pad_handler : : send_output_report ( DualSenseDevice * device )
2020-12-13 00:00:45 +01:00
{
2021-02-11 23:27:33 +01:00
if ( ! device | | ! device - > hidDevice )
2020-12-13 00:00:45 +01:00
return - 2 ;
2021-04-07 23:05:18 +02:00
const auto config = device - > config ;
2020-12-14 14:33:43 +01:00
if ( config = = nullptr )
2020-12-13 00:00:45 +01:00
return - 2 ; // hid_write and hid_write_control return -1 on error
2021-02-08 23:58:24 +01:00
output_report_common common { } ;
2021-03-05 22:08:13 +01:00
// Only initialize lightbar in the first output report. The controller didn't seem to update the player LEDs correctly otherwise. (Might be placebo)
2021-02-09 00:31:07 +01:00
if ( device - > init_lightbar )
{
device - > init_lightbar = false ;
2021-03-05 22:08:13 +01:00
device - > lightbar_on = true ;
device - > lightbar_on_old = true ;
2021-02-09 00:31:07 +01:00
2021-02-09 01:02:59 +01:00
common . valid_flag_2 | = VALID_FLAG_2_LIGHTBAR_SETUP_CONTROL_ENABLE ;
2021-02-09 00:31:07 +01:00
common . lightbar_setup = LIGHTBAR_SETUP_LIGHT_OUT ; // Fade light out.
}
2021-03-05 20:32:58 +01:00
else
2021-02-09 00:31:07 +01:00
{
2021-03-05 20:32:58 +01:00
common . valid_flag_0 | = VALID_FLAG_0_COMPATIBLE_VIBRATION ;
common . valid_flag_0 | = VALID_FLAG_0_HAPTICS_SELECT ;
common . motor_left = device - > large_motor ;
common . motor_right = device - > small_motor ;
2021-02-09 00:31:07 +01:00
2021-03-05 20:32:58 +01:00
if ( device - > update_lightbar )
{
device - > update_lightbar = false ;
2021-02-09 01:02:59 +01:00
2021-03-05 20:32:58 +01:00
common . valid_flag_1 | = VALID_FLAG_1_LIGHTBAR_CONTROL_ENABLE ;
2021-03-05 22:08:13 +01:00
if ( device - > lightbar_on )
{
common . lightbar_r = config - > colorR ; // red
common . lightbar_g = config - > colorG ; // green
common . lightbar_b = config - > colorB ; // blue
}
else
{
common . lightbar_r = 0 ;
common . lightbar_g = 0 ;
common . lightbar_b = 0 ;
}
device - > lightbar_on_old = device - > lightbar_on ;
2021-03-05 20:32:58 +01:00
}
2021-02-09 02:24:33 +01:00
2021-03-05 20:32:58 +01:00
if ( device - > update_player_leds )
2021-02-09 02:24:33 +01:00
{
2021-03-05 20:32:58 +01:00
device - > update_player_leds = false ;
// The dualsense controller uses 5 LEDs to indicate the player ID.
// Use OR with 0x1, 0x2, 0x4, 0x8 and 0x10 to enable the LEDs (from leftmost to rightmost).
common . valid_flag_1 | = VALID_FLAG_1_PLAYER_INDICATOR_CONTROL_ENABLE ;
2021-08-09 23:41:49 +02:00
switch ( device - > player_id )
2021-03-05 20:32:58 +01:00
{
case 0 : common . player_leds = 0b00100 ; break ;
case 1 : common . player_leds = 0b01010 ; break ;
case 2 : common . player_leds = 0b10101 ; break ;
case 3 : common . player_leds = 0b11011 ; break ;
case 4 : common . player_leds = 0b11111 ; break ;
case 5 : common . player_leds = 0b10111 ; break ;
case 6 : common . player_leds = 0b11101 ; break ;
default :
2021-08-09 23:41:49 +02:00
fmt : : throw_exception ( " Dualsense is using forbidden player id %d " , device - > player_id ) ;
2021-03-05 20:32:58 +01:00
}
2021-02-09 02:24:33 +01:00
}
2021-02-09 01:02:59 +01:00
}
2021-02-13 01:25:39 +01:00
if ( device - > bt_controller )
2020-12-13 00:00:45 +01:00
{
2021-02-08 23:58:24 +01:00
const u8 seq_tag = ( device - > bt_sequence < < 4 ) | 0x0 ;
if ( + + device - > bt_sequence > = 16 ) device - > bt_sequence = 0 ;
2020-12-13 00:00:45 +01:00
2021-02-08 23:58:24 +01:00
output_report_bt report { } ;
report . report_id = 0x31 ; // report id for bluetooth
report . seq_tag = seq_tag ;
report . tag = 0x10 ; // magic number
2021-04-07 23:05:18 +02:00
report . common = common ;
2020-12-13 00:00:45 +01:00
const u8 btHdr = 0xA2 ;
const u32 crcHdr = CRCPP : : CRC : : Calculate ( & btHdr , 1 , crcTable ) ;
2021-02-08 23:58:24 +01:00
const u32 crcCalc = CRCPP : : CRC : : Calculate ( & report . report_id , ( DUALSENSE_BLUETOOTH_REPORT_SIZE - 4 ) , crcTable , crcHdr ) ;
2020-12-13 00:00:45 +01:00
2021-02-08 23:58:24 +01:00
report . crc32 [ 0 ] = ( crcCalc > > 0 ) & 0xFF ;
report . crc32 [ 1 ] = ( crcCalc > > 8 ) & 0xFF ;
report . crc32 [ 2 ] = ( crcCalc > > 16 ) & 0xFF ;
report . crc32 [ 3 ] = ( crcCalc > > 24 ) & 0xFF ;
2020-12-13 00:00:45 +01:00
2021-02-08 23:58:24 +01:00
return hid_write ( device - > hidDevice , & report . report_id , DUALSENSE_BLUETOOTH_REPORT_SIZE ) ;
2020-12-13 00:00:45 +01:00
}
else
{
2021-02-08 23:58:24 +01:00
output_report_usb report { } ;
report . report_id = 0x02 ; // report id for usb
2021-04-07 23:05:18 +02:00
report . common = common ;
2020-12-13 00:00:45 +01:00
2021-02-08 23:58:24 +01:00
return hid_write ( device - > hidDevice , & report . report_id , DUALSENSE_USB_REPORT_SIZE ) ;
2020-12-13 00:00:45 +01:00
}
}
void dualsense_pad_handler : : apply_pad_data ( const std : : shared_ptr < PadDevice > & device , const std : : shared_ptr < Pad > & pad )
{
2021-02-11 23:27:33 +01:00
DualSenseDevice * dualsense_dev = static_cast < DualSenseDevice * > ( device . get ( ) ) ;
2021-02-12 01:44:39 +01:00
if ( ! dualsense_dev | | ! dualsense_dev - > hidDevice | | ! dualsense_dev - > config | | ! pad )
2020-12-13 00:00:45 +01:00
return ;
2021-08-10 21:45:26 +02:00
cfg_pad * config = dualsense_dev - > config ;
2020-12-13 00:00:45 +01:00
// Attempt to send rumble no matter what
2020-12-14 14:33:43 +01:00
const int idx_l = config - > switch_vibration_motors ? 1 : 0 ;
const int idx_s = config - > switch_vibration_motors ? 0 : 1 ;
2020-12-13 00:00:45 +01:00
2020-12-14 14:33:43 +01:00
const int speed_large = config - > enable_vibration_motor_large ? pad - > m_vibrateMotors [ idx_l ] . m_value : vibration_min ;
const int speed_small = config - > enable_vibration_motor_small ? pad - > m_vibrateMotors [ idx_s ] . m_value : vibration_min ;
2020-12-13 00:00:45 +01:00
2021-03-03 00:33:10 +01:00
const bool wireless = dualsense_dev - > cable_state = = 0 ;
2021-03-05 20:32:58 +01:00
const bool low_battery = dualsense_dev - > battery_level < = 1 ;
2021-03-03 00:33:10 +01:00
const bool is_blinking = dualsense_dev - > led_delay_on > 0 | | dualsense_dev - > led_delay_off > 0 ;
// Blink LED when battery is low
if ( config - > led_low_battery_blink )
{
// we are now wired or have okay battery level -> stop blinking
if ( is_blinking & & ! ( wireless & & low_battery ) )
{
2021-03-05 22:08:13 +01:00
dualsense_dev - > lightbar_on = true ;
2021-03-03 00:33:10 +01:00
dualsense_dev - > led_delay_on = 0 ;
dualsense_dev - > led_delay_off = 0 ;
dualsense_dev - > update_lightbar = true ;
}
// we are now wireless and low on battery -> blink
else if ( ! is_blinking & & wireless & & low_battery )
{
dualsense_dev - > led_delay_on = 100 ;
dualsense_dev - > led_delay_off = 100 ;
dualsense_dev - > update_lightbar = true ;
}
2021-03-05 22:08:13 +01:00
// Turn lightbar on and off in an interval. I wanted to do an automatic pulse, but I haven't found out how to do that yet.
if ( dualsense_dev - > led_delay_on > 0 )
{
2021-04-07 23:05:18 +02:00
if ( const steady_clock : : time_point now = steady_clock : : now ( ) ; ( now - dualsense_dev - > last_lightbar_time ) > 500 ms )
2021-03-05 22:08:13 +01:00
{
dualsense_dev - > lightbar_on = ! dualsense_dev - > lightbar_on ;
dualsense_dev - > last_lightbar_time = now ;
dualsense_dev - > update_lightbar = true ;
}
}
}
else if ( ! dualsense_dev - > lightbar_on )
{
dualsense_dev - > lightbar_on = true ;
dualsense_dev - > update_lightbar = true ;
2021-03-03 00:33:10 +01:00
}
// Use LEDs to indicate battery level
if ( config - > led_battery_indicator )
{
// This makes sure that the LED color doesn't update every 1ms. DS4 only reports battery level in 10% increments
if ( dualsense_dev - > last_battery_level ! = dualsense_dev - > battery_level )
{
const u32 combined_color = get_battery_color ( dualsense_dev - > battery_level , config - > led_battery_indicator_brightness ) ;
config - > colorR . set ( combined_color > > 8 ) ;
config - > colorG . set ( combined_color & 0xff ) ;
config - > colorB . set ( 0 ) ;
dualsense_dev - > update_lightbar = true ;
2021-03-05 22:08:13 +01:00
dualsense_dev - > last_battery_level = dualsense_dev - > battery_level ;
2021-03-03 00:33:10 +01:00
}
}
2021-03-06 10:43:01 +01:00
dualsense_dev - > new_output_data | = dualsense_dev - > update_lightbar | | dualsense_dev - > large_motor ! = speed_large | | dualsense_dev - > small_motor ! = speed_small ;
2020-12-13 00:00:45 +01:00
2021-02-11 23:27:33 +01:00
dualsense_dev - > large_motor = speed_large ;
dualsense_dev - > small_motor = speed_small ;
2020-12-13 00:00:45 +01:00
2021-02-12 01:44:39 +01:00
if ( dualsense_dev - > new_output_data )
2020-12-13 00:00:45 +01:00
{
2021-02-08 22:57:07 +01:00
if ( send_output_report ( dualsense_dev ) > = 0 )
2020-12-13 00:00:45 +01:00
{
2021-02-12 01:44:39 +01:00
dualsense_dev - > new_output_data = false ;
2020-12-13 00:00:45 +01:00
}
}
}
2021-02-08 23:05:37 +01:00
2021-08-09 23:41:49 +02:00
void dualsense_pad_handler : : SetPadData ( const std : : string & padId , u8 player_id , u32 largeMotor , u32 smallMotor , s32 r , s32 g , s32 b , bool battery_led , u32 battery_led_brightness )
2021-02-08 23:05:37 +01:00
{
2021-02-11 23:27:33 +01:00
std : : shared_ptr < DualSenseDevice > device = get_hid_device ( padId ) ;
2021-02-08 23:05:37 +01:00
if ( device = = nullptr | | device - > hidDevice = = nullptr )
return ;
// Set the device's motor speeds to our requested values 0-255
2021-02-11 23:27:33 +01:00
device - > large_motor = largeMotor ;
device - > small_motor = smallMotor ;
2021-08-09 23:41:49 +02:00
device - > player_id = player_id ;
2021-02-08 23:05:37 +01:00
int index = 0 ;
for ( uint i = 0 ; i < MAX_GAMEPADS ; i + + )
{
if ( g_cfg_input . player [ i ] - > handler = = m_type )
{
if ( g_cfg_input . player [ i ] - > device . to_string ( ) = = padId )
{
2021-08-10 21:45:26 +02:00
m_pad_configs [ index ] . from_string ( g_cfg_input . player [ i ] - > config . to_string ( ) ) ;
2021-02-08 23:05:37 +01:00
device - > config = & m_pad_configs [ index ] ;
break ;
}
index + + ;
}
}
2021-02-28 04:32:08 +01:00
ensure ( device - > config ) ;
2021-03-05 20:32:58 +01:00
device - > update_lightbar = true ;
2021-02-28 04:32:08 +01:00
2021-02-09 00:31:07 +01:00
// Set new LED color (see ds4_pad_handler)
2021-03-03 00:33:10 +01:00
if ( battery_led )
{
const u32 combined_color = get_battery_color ( device - > battery_level , battery_led_brightness ) ;
device - > config - > colorR . set ( combined_color > > 8 ) ;
device - > config - > colorG . set ( combined_color & 0xff ) ;
device - > config - > colorB . set ( 0 ) ;
}
else if ( r > = 0 & & g > = 0 & & b > = 0 & & r < = 255 & & g < = 255 & & b < = 255 )
2021-02-08 23:05:37 +01:00
{
device - > config - > colorR . set ( r ) ;
device - > config - > colorG . set ( g ) ;
device - > config - > colorB . set ( b ) ;
2021-03-05 20:32:58 +01:00
}
if ( device - > init_lightbar )
{
// Initialize first
send_output_report ( device . get ( ) ) ;
2021-02-08 23:05:37 +01:00
}
// Start/Stop the engines :)
2021-02-11 23:27:33 +01:00
send_output_report ( device . get ( ) ) ;
2021-02-08 23:05:37 +01:00
}
2021-03-03 00:33:10 +01:00
u32 dualsense_pad_handler : : get_battery_level ( const std : : string & padId )
{
2021-04-07 23:05:18 +02:00
const std : : shared_ptr < DualSenseDevice > device = get_hid_device ( padId ) ;
2021-03-03 00:33:10 +01:00
if ( device = = nullptr | | device - > hidDevice = = nullptr )
{
return 0 ;
}
2021-03-05 20:32:58 +01:00
return std : : min < u32 > ( device - > battery_level * 10 + 5 , 100 ) ; // 10% per unit, starting with 0-9%. So 100% equals unit 10
2021-03-03 00:33:10 +01:00
}