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"
2024-06-26 20:48:52 +02:00
# include <limits>
2020-12-13 00:00:45 +01:00
LOG_CHANNEL ( dualsense_log , " DualSense " ) ;
2024-06-27 20:37:33 +02:00
using namespace reports ;
2021-02-13 01:25:39 +01:00
template < >
void fmt_class_string < DualSenseDevice : : DualSenseDataMode > : : format ( std : : string & out , u64 arg )
{
2023-06-12 00:10:52 +02:00
format_enum ( out , arg , [ ] ( DualSenseDevice : : DualSenseDataMode mode )
2021-02-13 01:25:39 +01:00
{
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
{
2023-06-12 00:10:52 +02:00
constexpr id_pair SONY_DUALSENSE_ID_0 = { 0x054C , 0x0CE6 } ; // DualSense
constexpr id_pair SONY_DUALSENSE_ID_1 = { 0x054C , 0x0DF2 } ; // DualSense Edge
2020-12-13 00:00:45 +01:00
}
2024-06-11 22:30:16 +02:00
dualsense_pad_handler : : dualsense_pad_handler ( )
: hid_pad_handler < DualSenseDevice > ( pad_handler : : dualsense , { SONY_DUALSENSE_ID_0 , SONY_DUALSENSE_ID_1 } )
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+ " } ,
2023-06-12 05:28:49 +02:00
{ DualSenseKeyCodes : : RSYNeg , " RS Y- " } ,
{ DualSenseKeyCodes : : EdgeFnL , " FN L " } ,
{ DualSenseKeyCodes : : EdgeFnR , " FN R " } ,
{ DualSenseKeyCodes : : EdgeLB , " LB " } ,
{ DualSenseKeyCodes : : EdgeRB , " RB " } ,
2020-12-13 00:00:45 +01:00
} ;
init_configs ( ) ;
// Define border values
thumb_max = 255 ;
trigger_min = 0 ;
trigger_max = 255 ;
// Set capabilities
b_has_config = true ;
b_has_rumble = true ;
2022-08-13 09:56:04 +02:00
b_has_motion = true ;
2020-12-13 00:00:45 +01:00
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 ;
2022-10-19 21:47:18 +02:00
b_has_player_led = true ;
2021-03-03 00:33:10 +01:00
b_has_battery = true ;
2024-07-06 17:46:37 +02:00
b_has_battery_led = 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 ;
}
2024-04-28 13:13:47 +02:00
std : : array < u8 , std : : max ( DUALSENSE_FIRMWARE_REPORT_SIZE , DUALSENSE_PAIRING_REPORT_SIZE ) > 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.
2022-06-05 15:20:38 +02:00
int res = hid_get_feature_report ( hidDevice , buf . data ( ) , buf . size ( ) ) ;
if ( res < 0 | | buf [ 0 ] ! = 0x09 )
2021-10-01 01:47:14 +02:00
{
2022-06-05 15:20:38 +02:00
dualsense_log . error ( " check_add_device: hid_get_feature_report 0x09 failed! result=%d, buf[0]=0x%x, error=%s " , res , buf [ 0 ] , hid_error ( hidDevice ) ) ;
2023-08-28 20:53:02 +02:00
hid_close ( hidDevice ) ;
2021-10-01 01:47:14 +02:00
return ;
}
2023-06-12 01:05:31 +02:00
std : : string serial ;
2021-10-01 01:47:14 +02:00
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! " ) ;
2024-06-30 11:32:44 +02:00
device - > close ( ) ;
2021-02-04 22:05:12 +01:00
return ;
}
2021-03-05 19:14:50 +01:00
u32 hw_version { } ;
2022-10-22 02:37:49 +02:00
u16 fw_version { } ;
u32 fw_version2 { } ;
2021-03-05 19:14:50 +01:00
2022-06-05 14:03:00 +02:00
buf = { } ;
2021-03-05 19:14:50 +01:00
buf [ 0 ] = 0x20 ;
2021-10-01 01:47:14 +02:00
2024-04-28 13:13:47 +02:00
res = hid_get_feature_report ( hidDevice , buf . data ( ) , DUALSENSE_FIRMWARE_REPORT_SIZE ) ;
if ( res ! = DUALSENSE_FIRMWARE_REPORT_SIZE | | buf [ 0 ] ! = 0x20 ) // Old versions return 65, newer versions return 64
2021-03-05 19:14:50 +01:00
{
2022-06-05 15:20:38 +02:00
dualsense_log . error ( " check_add_device: hid_get_feature_report 0x20 failed! Could not retrieve firmware version! result=%d, buf[0]=0x%x, error=%s " , res , buf [ 0 ] , hid_error ( hidDevice ) ) ;
2021-03-05 19:14:50 +01:00
}
else
{
2022-06-05 15:20:38 +02:00
hw_version = read_u32 ( & buf [ 24 ] ) ;
2022-10-22 02:37:49 +02:00
fw_version2 = read_u32 ( & buf [ 28 ] ) ;
fw_version = static_cast < u16 > ( buf [ 44 ] ) | ( static_cast < u16 > ( buf [ 45 ] ) < < 8 ) ;
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 ) ) ;
2024-06-30 11:32:44 +02:00
device - > close ( ) ;
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
2023-06-12 05:28:49 +02:00
// Get feature set
if ( const hid_device_info * info = hid_get_device_info ( device - > hidDevice ) )
{
if ( info - > product_id = = SONY_DUALSENSE_ID_1 . m_pid )
{
device - > feature_set = DualSenseDevice : : DualSenseFeatureSet : : Edge ;
dualsense_log . notice ( " check_add_device: device is DualSense Edge: vid=0x%x, pid=0x%x, path='%s' " , info - > vendor_id , info - > product_id , path ) ;
}
}
else
{
dualsense_log . warning ( " check_add_device: hid_get_device_info failed for determining feature set! Reason: %s " , hid_error ( hidDevice ) ) ;
}
2021-02-13 01:25:39 +01:00
// Activate
2023-05-25 22:07:41 +02:00
if ( send_output_report ( device ) = = - 1 )
{
dualsense_log . error ( " check_add_device: send_output_report failed! Reason: %s " , hid_error ( hidDevice ) ) ;
}
2021-02-13 01:25:39 +01:00
// Get bluetooth information
get_data ( device ) ;
2022-10-22 02:37:49 +02:00
dualsense_log . notice ( " Added device: bluetooth=%d, data_mode=%s, serial='%s', hw_version: 0x%x, fw_version: 0x%x (0x%x), path='%s' " , device - > bt_controller , device - > data_mode , serial , hw_version , fw_version , fw_version2 , 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
2022-09-19 14:57:51 +02:00
cfg - > ls_left . def = : : at32 ( button_list , DualSenseKeyCodes : : LSXNeg ) ;
cfg - > ls_down . def = : : at32 ( button_list , DualSenseKeyCodes : : LSYNeg ) ;
cfg - > ls_right . def = : : at32 ( button_list , DualSenseKeyCodes : : LSXPos ) ;
cfg - > ls_up . def = : : at32 ( button_list , DualSenseKeyCodes : : LSYPos ) ;
cfg - > rs_left . def = : : at32 ( button_list , DualSenseKeyCodes : : RSXNeg ) ;
cfg - > rs_down . def = : : at32 ( button_list , DualSenseKeyCodes : : RSYNeg ) ;
cfg - > rs_right . def = : : at32 ( button_list , DualSenseKeyCodes : : RSXPos ) ;
cfg - > rs_up . def = : : at32 ( button_list , DualSenseKeyCodes : : RSYPos ) ;
cfg - > start . def = : : at32 ( button_list , DualSenseKeyCodes : : Options ) ;
cfg - > select . def = : : at32 ( button_list , DualSenseKeyCodes : : Share ) ;
cfg - > ps . def = : : at32 ( button_list , DualSenseKeyCodes : : PSButton ) ;
cfg - > square . def = : : at32 ( button_list , DualSenseKeyCodes : : Square ) ;
cfg - > cross . def = : : at32 ( button_list , DualSenseKeyCodes : : Cross ) ;
cfg - > circle . def = : : at32 ( button_list , DualSenseKeyCodes : : Circle ) ;
cfg - > triangle . def = : : at32 ( button_list , DualSenseKeyCodes : : Triangle ) ;
cfg - > left . def = : : at32 ( button_list , DualSenseKeyCodes : : Left ) ;
cfg - > down . def = : : at32 ( button_list , DualSenseKeyCodes : : Down ) ;
cfg - > right . def = : : at32 ( button_list , DualSenseKeyCodes : : Right ) ;
cfg - > up . def = : : at32 ( button_list , DualSenseKeyCodes : : Up ) ;
cfg - > r1 . def = : : at32 ( button_list , DualSenseKeyCodes : : R1 ) ;
cfg - > r2 . def = : : at32 ( button_list , DualSenseKeyCodes : : R2 ) ;
cfg - > r3 . def = : : at32 ( button_list , DualSenseKeyCodes : : R3 ) ;
cfg - > l1 . def = : : at32 ( button_list , DualSenseKeyCodes : : L1 ) ;
cfg - > l2 . def = : : at32 ( button_list , DualSenseKeyCodes : : L2 ) ;
cfg - > l3 . def = : : at32 ( button_list , DualSenseKeyCodes : : L3 ) ;
cfg - > pressure_intensity_button . def = : : at32 ( button_list , DualSenseKeyCodes : : None ) ;
2021-08-06 02:08:18 +02:00
2020-12-13 00:00:45 +01:00
// Set default misc variables
2024-05-27 21:50:09 +02:00
cfg - > lstick_anti_deadzone . def = static_cast < u32 > ( 0.13 * thumb_max ) ; // 13%
cfg - > rstick_anti_deadzone . def = static_cast < u32 > ( 0.13 * thumb_max ) ; // 13%
2020-12-13 00:00:45 +01:00
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 { } ;
2023-08-26 15:47:52 +02:00
const int res = hid_read ( device - > hidDevice , buf . data ( ) , buf . size ( ) ) ;
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 ;
2024-04-28 13:13:47 +02:00
2020-12-13 00:00:45 +01:00
switch ( buf [ 0 ] )
{
case 0x01 :
2021-02-04 22:05:12 +01:00
{
2024-04-28 13:13:47 +02:00
if ( res = = sizeof ( dualsense_input_report_bt ) )
2020-12-13 00:00:45 +01:00
{
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
}
else
{
2021-02-13 01:25:39 +01:00
device - > data_mode = DualSenseDevice : : DualSenseDataMode : : Enhanced ;
device - > bt_controller = false ;
2020-12-13 00:00:45 +01:00
}
2024-04-28 13:13:47 +02:00
offset = offsetof ( dualsense_input_report_usb , common ) ;
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 ;
2024-04-28 13:13:47 +02:00
offset = offsetof ( dualsense_input_report_bt , common ) ;
2020-12-13 00:00:45 +01:00
const u8 btHdr = 0xA1 ;
const u32 crcHdr = CRCPP : : CRC : : Calculate ( & btHdr , 1 , crcTable ) ;
2024-04-28 13:13:47 +02:00
const u32 crcCalc = CRCPP : : CRC : : Calculate ( buf . data ( ) , offsetof ( dualsense_input_report_bt , crc32 ) , crcTable , crcHdr ) ;
const u32 crcReported = read_u32 ( & buf [ offsetof ( dualsense_input_report_bt , crc32 ) ] ) ;
2020-12-13 00:00:45 +01:00
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 )
{
2024-04-28 13:13:47 +02:00
int calib_offset = offset + offsetof ( dualsense_input_report_common , gyro ) ;
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 ;
}
}
2024-04-28 13:13:47 +02:00
std : : memcpy ( & device - > report , & buf [ offset ] , sizeof ( dualsense_input_report_common ) ) ;
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 )
{
2024-04-28 13:13:47 +02:00
const u8 battery_state = device - > report . status ;
2021-03-03 00:33:10 +01:00
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 ;
}
}
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 ;
}
2022-06-05 14:03:00 +02:00
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 )
{
2022-06-05 14:35:58 +02:00
buf = { } ;
2021-02-04 22:05:12 +01:00
buf [ 0 ] = 0x05 ;
2022-06-05 15:20:38 +02:00
if ( int res = hid_get_feature_report ( dualsense_device - > hidDevice , buf . data ( ) , DUALSENSE_CALIBRATION_REPORT_SIZE ) ; res ! = DUALSENSE_CALIBRATION_REPORT_SIZE | | buf [ 0 ] ! = 0x05 )
2021-02-04 22:05:12 +01:00
{
2022-06-05 15:20:38 +02:00
dualsense_log . error ( " get_calibration_data: hid_get_feature_report 0x05 for bluetooth controller failed! result=%d, buf[0]=0x%x, error=%s " , res , buf [ 0 ] , 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 ;
2022-06-05 15:20:38 +02:00
if ( int res = hid_get_feature_report ( dualsense_device - > hidDevice , buf . data ( ) , DUALSENSE_CALIBRATION_REPORT_SIZE ) ; res ! = DUALSENSE_CALIBRATION_REPORT_SIZE | | buf [ 0 ] ! = 0x05 )
2021-02-04 22:05:12 +01:00
{
2022-06-05 15:20:38 +02:00
dualsense_log . error ( " get_calibration_data: hid_get_feature_report 0x05 for wired controller failed! result=%d, buf[0]=0x%x, error=%s " , res , buf [ 0 ] , 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
2024-06-26 20:52:18 +02:00
const s16 pitch_plus = read_s16 ( & buf [ 7 ] ) ;
const s16 pitch_minus = read_s16 ( & buf [ 9 ] ) ;
const s16 yaw_plus = read_s16 ( & buf [ 11 ] ) ;
const s16 yaw_minus = read_s16 ( & buf [ 13 ] ) ;
const s16 roll_plus = read_s16 ( & buf [ 15 ] ) ;
const s16 roll_minus = read_s16 ( & buf [ 17 ] ) ;
2021-02-04 22:05:12 +01:00
// 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 ) ;
}
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
2024-06-26 20:48:52 +02:00
for ( size_t i = 0 ; i < dualsense_device - > calib_data . size ( ) ; i + + )
2021-02-04 22:05:12 +01:00
{
2024-06-26 20:48:52 +02:00
CalibData & data = dualsense_device - > calib_data [ i ] ;
2021-02-04 22:05:12 +01:00
if ( data . sens_denom = = 0 )
{
2024-06-26 20:48:52 +02:00
dualsense_log . error ( " GetCalibrationData: Invalid accelerometer calibration data for axis %d, disabling calibration. " , i ) ;
data . bias = 0 ;
data . sens_numer = 4 * DUALSENSE_ACC_RES_PER_G ;
data . sens_denom = std : : numeric_limits < s16 > : : max ( ) ;
2021-02-04 22:05:12 +01:00
}
}
return true ;
}
2022-10-15 12:41:21 +02:00
bool dualsense_pad_handler : : get_is_left_trigger ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 keyCode )
2020-12-13 00:00:45 +01:00
{
return keyCode = = DualSenseKeyCodes : : L2 ;
}
2022-10-15 12:41:21 +02:00
bool dualsense_pad_handler : : get_is_right_trigger ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 keyCode )
2020-12-13 00:00:45 +01:00
{
return keyCode = = DualSenseKeyCodes : : R2 ;
}
2022-10-15 12:41:21 +02:00
bool dualsense_pad_handler : : get_is_left_stick ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 keyCode )
2020-12-13 00:00:45 +01:00
{
switch ( keyCode )
{
case DualSenseKeyCodes : : LSXNeg :
case DualSenseKeyCodes : : LSXPos :
case DualSenseKeyCodes : : LSYPos :
case DualSenseKeyCodes : : LSYNeg :
return true ;
default :
return false ;
}
}
2022-10-15 12:41:21 +02:00
bool dualsense_pad_handler : : get_is_right_stick ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 keyCode )
2020-12-13 00:00:45 +01:00
{
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
2024-06-30 11:32:44 +02:00
dualsense_dev - > close ( ) ;
2020-12-13 00:00:45 +01:00
return connection : : no_data ;
}
return connection : : connected ;
}
2022-08-13 09:56:04 +02:00
void dualsense_pad_handler : : get_extended_info ( const pad_ensemble & binding )
2021-02-04 22:05:12 +01:00
{
2022-08-13 09:56:04 +02:00
const auto & device = binding . device ;
const auto & pad = binding . 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
2024-04-28 13:13:47 +02:00
const dualsense_input_report_common & input = dualsense_device - > report ;
2021-03-02 23:24:05 +01:00
2021-02-04 22:05:12 +01:00
// these values come already calibrated, all we need to do is convert to ds3 range
2022-10-17 22:41:34 +02:00
// gyroY is yaw, which is all that we need
2024-04-28 13:13:47 +02:00
//f32 gyroX = static_cast<s16>(input.gyro[0]) / static_cast<f32>(DUALSENSE_GYRO_RES_PER_DEG_S) * -1.f;
f32 gyroY = static_cast < s16 > ( input . gyro [ 1 ] ) / static_cast < f32 > ( DUALSENSE_GYRO_RES_PER_DEG_S ) * - 1.f ;
//f32 gyroZ = static_cast<s16>(input.gyro[2]) / static_cast<f32>(DUALSENSE_GYRO_RES_PER_DEG_S) * -1.f;
2021-02-04 22:05:12 +01:00
// accel
2024-04-28 13:13:47 +02:00
f32 accelX = static_cast < s16 > ( input . accel [ 0 ] ) / static_cast < f32 > ( DUALSENSE_ACC_RES_PER_G ) * - 1 ;
f32 accelY = static_cast < s16 > ( input . accel [ 1 ] ) / static_cast < f32 > ( DUALSENSE_ACC_RES_PER_G ) * - 1 ;
f32 accelZ = static_cast < s16 > ( input . accel [ 2 ] ) / static_cast < f32 > ( DUALSENSE_ACC_RES_PER_G ) * - 1 ;
2021-02-04 22:05:12 +01:00
// now just use formula from ds3
accelX = accelX * 113 + 512 ;
accelY = accelY * 113 + 512 ;
accelZ = accelZ * 113 + 512 ;
2022-10-17 22:41:34 +02:00
// Convert to ds3. The ds3 resolution is 123/90°/sec.
gyroY = gyroY * ( 123.f / 90.f ) + 512 ;
2021-02-04 22:05:12 +01:00
pad - > m_sensors [ 0 ] . m_value = Clamp0To1023 ( accelX ) ;
pad - > m_sensors [ 1 ] . m_value = Clamp0To1023 ( accelY ) ;
pad - > m_sensors [ 2 ] . m_value = Clamp0To1023 ( accelZ ) ;
2022-10-17 22:41:34 +02:00
pad - > m_sensors [ 3 ] . m_value = Clamp0To1023 ( gyroY ) ;
2021-02-04 22:05:12 +01:00
}
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 ;
2024-04-28 13:13:47 +02:00
const dualsense_input_report_common & input = dualsense_dev - > report ;
2020-12-13 00:00:45 +01:00
2023-06-12 01:05:31 +02:00
const bool is_simple_mode = dualsense_dev - > data_mode = = DualSenseDevice : : DualSenseDataMode : : Simple ;
2020-12-13 00:00:45 +01:00
// Left Stick X Axis
2024-04-28 13:13:47 +02:00
keyBuffer [ DualSenseKeyCodes : : LSXNeg ] = Clamp0To255 ( ( 127.5f - input . x ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : LSXPos ] = Clamp0To255 ( ( input . x - 127.5f ) * 2.0f ) ;
2020-12-13 00:00:45 +01:00
// Left Stick Y Axis (Up is the negative for some reason)
2024-04-28 13:13:47 +02:00
keyBuffer [ DualSenseKeyCodes : : LSYNeg ] = Clamp0To255 ( ( input . y - 127.5f ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : LSYPos ] = Clamp0To255 ( ( 127.5f - input . y ) * 2.0f ) ;
2020-12-13 00:00:45 +01:00
// Right Stick X Axis
2024-04-28 13:13:47 +02:00
keyBuffer [ DualSenseKeyCodes : : RSXNeg ] = Clamp0To255 ( ( 127.5f - input . rx ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : RSXPos ] = Clamp0To255 ( ( input . rx - 127.5f ) * 2.0f ) ;
2020-12-13 00:00:45 +01:00
// Right Stick Y Axis (Up is the negative for some reason)
2024-04-28 13:13:47 +02:00
keyBuffer [ DualSenseKeyCodes : : RSYNeg ] = Clamp0To255 ( ( input . ry - 127.5f ) * 2.0f ) ;
keyBuffer [ DualSenseKeyCodes : : RSYPos ] = Clamp0To255 ( ( 127.5f - input . ry ) * 2.0f ) ;
2020-12-13 00:00:45 +01:00
2024-04-28 13:13:47 +02:00
keyBuffer [ DualSenseKeyCodes : : L2 ] = is_simple_mode ? input . buttons [ 0 ] : input . z ;
keyBuffer [ DualSenseKeyCodes : : R2 ] = is_simple_mode ? input . buttons [ 1 ] : input . rz ;
2021-03-02 23:24:05 +01:00
2024-04-28 13:13:47 +02:00
u8 data = ( is_simple_mode ? input . z : input . buttons [ 0 ] ) & 0xf ;
2020-12-13 00:00:45 +01:00
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 " ) ;
}
2024-04-28 13:13:47 +02:00
data = ( is_simple_mode ? input . z : input . buttons [ 0 ] ) > > 4 ;
2020-12-13 00:00:45 +01:00
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 ;
2024-04-28 13:13:47 +02:00
data = ( is_simple_mode ? input . rz : input . buttons [ 1 ] ) ;
2020-12-13 00:00:45 +01:00
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 ;
2024-04-28 13:13:47 +02:00
data = ( is_simple_mode ? input . seq_number : input . buttons [ 2 ] ) ;
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
2023-06-12 05:28:49 +02:00
if ( dualsense_dev - > feature_set = = DualSenseDevice : : DualSenseFeatureSet : : Edge )
{
keyBuffer [ DualSenseKeyCodes : : EdgeFnL ] = ( ( data & 0x10 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : EdgeFnR ] = ( ( data & 0x20 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : EdgeLB ] = ( ( data & 0x40 ) ! = 0 ) ? 255 : 0 ;
keyBuffer [ DualSenseKeyCodes : : EdgeRB ] = ( ( data & 0x80 ) ! = 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 {
2022-09-19 14:57:51 +02:00
: : at32 ( data , L2 ) ,
: : at32 ( data , R2 ) ,
: : at32 ( data , LSXPos ) - : : at32 ( data , LSXNeg ) ,
: : at32 ( data , LSYPos ) - : : at32 ( data , LSYNeg ) ,
: : at32 ( data , RSXPos ) - : : at32 ( data , RSXNeg ) ,
: : at32 ( data , RSYPos ) - : : at32 ( data , RSYNeg )
2020-12-14 14:33:43 +01:00
} ;
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 ;
2024-04-28 13:13:47 +02:00
// Turns off the lights (disabled due to user complaints)
//controller.second->release_leds = true;
2021-02-11 23:27:33 +01:00
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 ;
2022-10-19 21:47:18 +02:00
const cfg_pad * config = device - > config ;
2020-12-14 14:33:43 +01:00
if ( config = = nullptr )
2023-05-25 21:53:20 +02:00
return - 2 ; // hid_write returns -1 on error
2020-12-13 00:00:45 +01:00
2024-04-28 13:13:47 +02:00
dualsense_output_report_common common { } ;
2021-02-08 23:58:24 +01:00
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 ;
2024-04-28 13:13:47 +02:00
common . lightbar_setup = LIGHTBAR_SETUP_LIGHT_OFF ; // Fade light out.
2021-02-09 00:31:07 +01:00
}
2022-10-22 01:58:45 +02:00
else if ( device - > release_leds )
{
common . valid_flag_1 | = VALID_FLAG_1_RELEASE_LEDS ;
device - > release_leds = false ;
}
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 ;
2022-10-22 02:40:53 +02:00
common . valid_flag_1 | = VALID_FLAG_1_POWER_SAVE_CONTROL_ENABLE ;
common . valid_flag_2 | = VALID_FLAG_2_IMPROVED_RUMBLE_EMULATION ;
2021-03-05 20:32:58 +01:00
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 ;
2022-10-19 21:47:18 +02:00
if ( config - > player_led_enabled )
2021-03-05 20:32:58 +01:00
{
2022-10-19 21:47:18 +02:00
switch ( device - > player_id )
{
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 :
fmt : : throw_exception ( " Dualsense is using forbidden player id %d " , device - > player_id ) ;
}
}
else
{
common . player_leds = 0 ;
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
2024-04-28 13:13:47 +02:00
dualsense_output_report_bt report { } ;
2021-02-08 23:58:24 +01:00
report . report_id = 0x31 ; // report id for bluetooth
report . seq_tag = seq_tag ;
report . tag = 0x10 ; // magic number
2024-04-28 13:13:47 +02:00
report . common = std : : move ( common ) ;
2020-12-13 00:00:45 +01:00
const u8 btHdr = 0xA2 ;
const u32 crcHdr = CRCPP : : CRC : : Calculate ( & btHdr , 1 , crcTable ) ;
2024-04-28 13:13:47 +02:00
const u32 crcCalc = CRCPP : : CRC : : Calculate ( & report . report_id , ( sizeof ( dualsense_output_report_bt ) - 4 ) , crcTable , crcHdr ) ;
2020-12-13 00:00:45 +01:00
2024-04-28 13:13:47 +02:00
write_to_ptr ( report . crc32 , crcCalc ) ;
2020-12-13 00:00:45 +01:00
2024-04-28 13:13:47 +02:00
return hid_write ( device - > hidDevice , & report . report_id , sizeof ( dualsense_output_report_bt ) ) ;
2020-12-13 00:00:45 +01:00
}
2024-04-28 13:13:47 +02:00
dualsense_output_report_usb report { } ;
2023-08-29 20:46:09 +02:00
report . report_id = 0x02 ; // report id for usb
2024-04-28 13:13:47 +02:00
report . common = std : : move ( common ) ;
2023-08-29 20:46:09 +02:00
return hid_write ( device - > hidDevice , & report . report_id , DUALSENSE_USB_REPORT_SIZE ) ;
2020-12-13 00:00:45 +01:00
}
2022-08-13 09:56:04 +02:00
void dualsense_pad_handler : : apply_pad_data ( const pad_ensemble & binding )
2020-12-13 00:00:45 +01:00
{
2022-08-13 09:56:04 +02:00
const auto & device = binding . device ;
const auto & pad = binding . 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
2022-10-21 22:35:31 +02:00
const u8 speed_large = config - > enable_vibration_motor_large ? pad - > m_vibrateMotors [ idx_l ] . m_value : 0 ;
const u8 speed_small = config - > enable_vibration_motor_small ? pad - > m_vibrateMotors [ idx_s ] . m_value : 0 ;
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 ;
2022-09-19 14:57:51 +02:00
2021-03-03 00:33:10 +01:00
// 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
}
}
2022-10-19 21:47:18 +02:00
if ( dualsense_dev - > enable_player_leds ! = config - > player_led_enabled . get ( ) )
{
dualsense_dev - > enable_player_leds = config - > player_led_enabled . get ( ) ;
dualsense_dev - > update_player_leds = true ;
}
2022-10-22 01:58:45 +02:00
dualsense_dev - > new_output_data | = dualsense_dev - > release_leds | | dualsense_dev - > update_player_leds | | 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
2022-10-21 22:35:31 +02:00
void dualsense_pad_handler : : SetPadData ( const std : : string & padId , u8 player_id , u8 large_motor , u8 small_motor , s32 r , s32 g , s32 b , bool player_led , 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
2022-10-21 22:35:31 +02:00
device - > large_motor = large_motor ;
device - > small_motor = small_motor ;
2021-08-09 23:41:49 +02:00
device - > player_id = player_id ;
2023-01-17 01:28:54 +01:00
device - > config = get_config ( padId ) ;
2021-02-08 23:05:37 +01:00
2021-02-28 04:32:08 +01:00
ensure ( device - > config ) ;
2021-03-05 20:32:58 +01:00
device - > update_lightbar = true ;
2022-10-19 21:47:18 +02:00
device - > update_player_leds = true ;
device - > config - > player_led_enabled . set ( player_led ) ;
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
}