dualsense: implement battery level

This commit is contained in:
Megamouse 2021-03-03 00:33:10 +01:00
parent b836d2497d
commit cdffaa1598
6 changed files with 109 additions and 19 deletions

View File

@ -768,20 +768,6 @@ bool ds4_pad_handler::get_is_right_stick(u64 keyCode)
}
}
u32 ds4_pad_handler::get_battery_color(u8 battery_level, int brightness)
{
static const std::array<u32, 12> battery_level_clr = {0xff00, 0xff33, 0xff66, 0xff99, 0xffcc, 0xffff, 0xccff, 0x99ff, 0x66ff, 0x33ff, 0x00ff, 0x00ff};
u32 combined_color = battery_level_clr[0];
// Check if we got a weird value
if (battery_level < battery_level_clr.size())
{
combined_color = battery_level_clr[battery_level];
}
const u32 red = (combined_color >> 8) * brightness / 100;
const u32 green = (combined_color & 0xff) * brightness / 100;
return ((red << 8) | green);
}
PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ptr<PadDevice>& device)
{
DS4Device* ds4_dev = static_cast<DS4Device*>(device.get());

View File

@ -62,8 +62,6 @@ public:
void init_config(pad_config* cfg, const std::string& name) override;
private:
u32 get_battery_color(u8 battery_level, int brightness);
// This function gets us usuable buffer from the rawbuffer of padData
bool GetCalibrationData(DS4Device* ds4Device);

View File

@ -138,7 +138,7 @@ dualsense_pad_handler::dualsense_pad_handler()
b_has_deadzones = true;
b_has_led = true;
b_has_rgb = true;
b_has_battery = false;
b_has_battery = true;
m_name_string = "DualSense Pad #";
m_max_devices = CELL_PAD_MAX_PORT_NUM;
@ -350,6 +350,35 @@ dualsense_pad_handler::DataStatus dualsense_pad_handler::get_data(DualSenseDevic
}
}
// 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:
device->battery_level = std::min(battery_value * 10 + 5, 100);
device->cable_state = 0;
break;
case 0x1:
device->battery_level = std::min(battery_value * 10 + 5, 100);
device->cable_state = 1;
break;
case 0x2:
device->battery_level = 100;
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;
}
}
memcpy(device->padData.data(), &buf[offset], 64);
return DataStatus::NewData;
}
@ -867,6 +896,7 @@ int dualsense_pad_handler::send_output_report(DualSenseDevice* device)
if (device->init_lightbar)
{
// TODO: these settings might need to be initialized on their own. Needs investigation.
device->init_lightbar = false;
common.valid_flag_2 |= VALID_FLAG_2_LIGHTBAR_SETUP_CONTROL_ENABLE;
@ -875,6 +905,7 @@ int dualsense_pad_handler::send_output_report(DualSenseDevice* device)
if (device->update_lightbar)
{
// TODO: battery blink
device->update_lightbar = false;
common.valid_flag_1 |= VALID_FLAG_1_LIGHTBAR_CONTROL_ENABLE;
@ -952,6 +983,46 @@ void dualsense_pad_handler::apply_pad_data(const std::shared_ptr<PadDevice>& dev
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;
const bool wireless = dualsense_dev->cable_state == 0;
const bool low_battery = dualsense_dev->battery_level <= 15;
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))
{
dualsense_dev->led_delay_on = 0;
dualsense_dev->led_delay_off = 0;
dualsense_dev->update_lightbar = true;
dualsense_dev->new_output_data = 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;
dualsense_dev->new_output_data = true;
}
}
// 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;
dualsense_dev->new_output_data = true;
}
}
dualsense_dev->new_output_data |= dualsense_dev->large_motor != speed_large || dualsense_dev->small_motor != speed_small;
dualsense_dev->large_motor = speed_large;
@ -966,7 +1037,7 @@ void dualsense_pad_handler::apply_pad_data(const std::shared_ptr<PadDevice>& dev
}
}
void dualsense_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool /*battery_led*/, u32 /*battery_led_brightness*/)
void dualsense_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness)
{
std::shared_ptr<DualSenseDevice> device = get_hid_device(padId);
if (device == nullptr || device->hidDevice == nullptr)
@ -994,7 +1065,14 @@ void dualsense_pad_handler::SetPadData(const std::string& padId, u32 largeMotor,
ensure(device->config);
// Set new LED color (see ds4_pad_handler)
if (r >= 0 && g >= 0 && b >= 0 && r <= 255 && g <= 255 && b <= 255)
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)
{
device->config->colorR.set(r);
device->config->colorG.set(g);
@ -1005,3 +1083,13 @@ void dualsense_pad_handler::SetPadData(const std::string& padId, u32 largeMotor,
// Start/Stop the engines :)
send_output_report(device.get());
}
u32 dualsense_pad_handler::get_battery_level(const std::string& padId)
{
std::shared_ptr<DualSenseDevice> device = get_hid_device(padId);
if (device == nullptr || device->hidDevice == nullptr)
{
return 0;
}
return std::min<u32>(device->battery_level, 100);
}

View File

@ -66,6 +66,7 @@ public:
~dualsense_pad_handler();
void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override;
u32 get_battery_level(const std::string& padId) override;
void init_config(pad_config* cfg, const std::string& name) override;
private:

View File

@ -203,6 +203,21 @@ std::shared_ptr<PadDevice> hid_pad_handler<Device>::get_device(const std::string
return get_hid_device(device);
}
template <class Device>
u32 hid_pad_handler<Device>::get_battery_color(u8 battery_level, int brightness) const
{
static const std::array<u32, 12> battery_level_clr = {0xff00, 0xff33, 0xff66, 0xff99, 0xffcc, 0xffff, 0xccff, 0x99ff, 0x66ff, 0x33ff, 0x00ff, 0x00ff};
u32 combined_color = battery_level_clr[0];
// Check if we got a weird value
if (battery_level < battery_level_clr.size())
{
combined_color = battery_level_clr[battery_level];
}
const u32 red = (combined_color >> 8) * brightness / 100;
const u32 green = (combined_color & 0xff) * brightness / 100;
return ((red << 8) | green);
}
template class hid_pad_handler<ds3_device>;
template class hid_pad_handler<DS4Device>;
template class hid_pad_handler<DualSenseDevice>;

View File

@ -102,6 +102,8 @@ protected:
return *reinterpret_cast<const u32*>(buf);
}
u32 get_battery_color(u8 battery_level, int brightness) const;
private:
std::shared_ptr<PadDevice> get_device(const std::string& device) override;
};