mirror of
https://gitlab.freedesktop.org/upower/upower.git
synced 2025-12-27 07:50:04 +01:00
linux: Use new battery class and drop unused code
This makes the switch. There are a few behaviour changes with regard to estimations (which hopefully got both simpler and more robust at the same time).
This commit is contained in:
parent
ed2d5a25b3
commit
6fedd0f20a
3 changed files with 22 additions and 621 deletions
|
|
@ -766,7 +766,7 @@ class Tests(dbusmock.DBusTestCase):
|
|||
self.stop_daemon()
|
||||
|
||||
def test_battery_energy_charge_mixed(self):
|
||||
'''battery which reports current energy, but full charge'''
|
||||
'''battery which reports both current charge and energy'''
|
||||
|
||||
self.testbed.add_device('power_supply', 'BAT0', None,
|
||||
['type', 'Battery',
|
||||
|
|
@ -774,7 +774,8 @@ class Tests(dbusmock.DBusTestCase):
|
|||
'status', 'Discharging',
|
||||
'charge_full', '10500000',
|
||||
'charge_full_design', '11000000',
|
||||
'energy_now', '50400000',
|
||||
'charge_now', '4200000',
|
||||
'energy_now', '9999999',
|
||||
'voltage_now', '12000000'], [])
|
||||
|
||||
self.start_daemon()
|
||||
|
|
@ -786,7 +787,7 @@ class Tests(dbusmock.DBusTestCase):
|
|||
self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE)
|
||||
self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IsPresent'), True)
|
||||
self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING)
|
||||
self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 50.4)
|
||||
self.assertAlmostEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 50.4)
|
||||
self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFull'), 126.0)
|
||||
self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFullDesign'), 132.0)
|
||||
self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Voltage'), 12.0)
|
||||
|
|
|
|||
|
|
@ -37,38 +37,16 @@
|
|||
#include "up-device-supply.h"
|
||||
#include "up-common.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_IGNORE_SYSTEM_PERCENTAGE
|
||||
};
|
||||
|
||||
#define UP_DEVICE_SUPPLY_COLDPLUG_UNITS_CHARGE TRUE
|
||||
#define UP_DEVICE_SUPPLY_COLDPLUG_UNITS_ENERGY FALSE
|
||||
|
||||
/* number of old energy values to keep cached */
|
||||
#define UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH 4
|
||||
|
||||
struct UpDeviceSupplyPrivate
|
||||
{
|
||||
gboolean has_coldplug_values;
|
||||
gboolean coldplug_units;
|
||||
gdouble *energy_old;
|
||||
GTimeVal *energy_old_timespec;
|
||||
guint energy_old_first;
|
||||
gdouble rate_old;
|
||||
gint64 fast_repoll_until;
|
||||
gboolean disable_battery_poll; /* from configuration */
|
||||
gboolean shown_invalid_voltage_warning;
|
||||
gboolean ignore_system_percentage;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (UpDeviceSupply, up_device_supply, UP_TYPE_DEVICE)
|
||||
|
||||
static gboolean up_device_supply_refresh (UpDevice *device,
|
||||
UpRefreshReason reason);
|
||||
static void up_device_supply_update_poll_frequency (UpDevice *device,
|
||||
UpDeviceState state,
|
||||
UpRefreshReason reason);
|
||||
static UpDeviceKind up_device_supply_guess_type (GUdevDevice *native,
|
||||
const char *native_path);
|
||||
|
||||
|
|
@ -102,21 +80,10 @@ up_device_supply_refresh_line_power (UpDeviceSupply *supply,
|
|||
static void
|
||||
up_device_supply_reset_values (UpDeviceSupply *supply)
|
||||
{
|
||||
UpDevice *device = UP_DEVICE (supply);
|
||||
guint i;
|
||||
|
||||
supply->priv->has_coldplug_values = FALSE;
|
||||
supply->priv->coldplug_units = UP_DEVICE_SUPPLY_COLDPLUG_UNITS_ENERGY;
|
||||
supply->priv->rate_old = 0;
|
||||
|
||||
for (i = 0; i < UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH; ++i) {
|
||||
supply->priv->energy_old[i] = 0.0f;
|
||||
supply->priv->energy_old_timespec[i].tv_sec = 0;
|
||||
}
|
||||
supply->priv->energy_old_first = 0;
|
||||
|
||||
/* reset to default */
|
||||
g_object_set (device,
|
||||
g_object_set (supply,
|
||||
"vendor", NULL,
|
||||
"model", NULL,
|
||||
"serial", NULL,
|
||||
|
|
@ -143,41 +110,6 @@ up_device_supply_reset_values (UpDeviceSupply *supply)
|
|||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_get_on_battery:
|
||||
**/
|
||||
static gboolean
|
||||
up_device_supply_get_on_battery (UpDevice *device, gboolean *on_battery)
|
||||
{
|
||||
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device);
|
||||
UpDeviceKind type;
|
||||
UpDeviceState state;
|
||||
gboolean is_power_supply;
|
||||
gboolean is_present;
|
||||
|
||||
g_return_val_if_fail (UP_IS_DEVICE_SUPPLY (supply), FALSE);
|
||||
g_return_val_if_fail (on_battery != NULL, FALSE);
|
||||
|
||||
g_object_get (device,
|
||||
"type", &type,
|
||||
"state", &state,
|
||||
"is-present", &is_present,
|
||||
"power-supply", &is_power_supply,
|
||||
NULL);
|
||||
|
||||
if (!is_power_supply)
|
||||
return FALSE;
|
||||
if (type != UP_DEVICE_KIND_BATTERY)
|
||||
return FALSE;
|
||||
if (state == UP_DEVICE_STATE_UNKNOWN)
|
||||
return FALSE;
|
||||
if (!is_present)
|
||||
return FALSE;
|
||||
|
||||
*on_battery = (state == UP_DEVICE_STATE_DISCHARGING);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_get_online:
|
||||
**/
|
||||
|
|
@ -204,93 +136,6 @@ up_device_supply_get_online (UpDevice *device, gboolean *online)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_push_new_energy:
|
||||
*
|
||||
* Store the new energy in the list of old energies of the supply, so
|
||||
* it can be used to determine the energy rate.
|
||||
*/
|
||||
static gboolean
|
||||
up_device_supply_push_new_energy (UpDeviceSupply *supply, gdouble energy)
|
||||
{
|
||||
guint first = supply->priv->energy_old_first;
|
||||
guint new_position = (first + UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH - 1) %
|
||||
UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH;
|
||||
|
||||
/* check if the energy value has changed and, if that's the case,
|
||||
* store the new values in the buffer. */
|
||||
if (supply->priv->energy_old[first] != energy) {
|
||||
supply->priv->energy_old[new_position] = energy;
|
||||
g_get_current_time (&supply->priv->energy_old_timespec[new_position]);
|
||||
supply->priv->energy_old_first = new_position;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_calculate_rate:
|
||||
**/
|
||||
static gdouble
|
||||
up_device_supply_calculate_rate (UpDeviceSupply *supply, gdouble energy)
|
||||
{
|
||||
gdouble rate = 0.0f;
|
||||
gdouble sum_x = 0.0f; /* sum of the squared times difference */
|
||||
GTimeVal now;
|
||||
guint i;
|
||||
guint valid_values = 0;
|
||||
|
||||
/* get the time difference from now and use linear regression to determine
|
||||
* the discharge rate of the battery. */
|
||||
g_get_current_time (&now);
|
||||
|
||||
/* store the data on the new energy received */
|
||||
up_device_supply_push_new_energy (supply, energy);
|
||||
|
||||
if (energy < 0.1f)
|
||||
return 0.0f;
|
||||
|
||||
if (supply->priv->energy_old[supply->priv->energy_old_first] < 0.1f)
|
||||
return 0.0f;
|
||||
|
||||
/* don't use the new point obtained since it may cause instability in
|
||||
* the estimate */
|
||||
i = supply->priv->energy_old_first;
|
||||
now = supply->priv->energy_old_timespec[i];
|
||||
do {
|
||||
/* only use this value if it seems valid */
|
||||
if (supply->priv->energy_old_timespec[i].tv_sec && supply->priv->energy_old[i]) {
|
||||
/* This is the square of t_i^2 */
|
||||
sum_x += (now.tv_sec - supply->priv->energy_old_timespec[i].tv_sec) *
|
||||
(now.tv_sec - supply->priv->energy_old_timespec[i].tv_sec);
|
||||
|
||||
/* Sum the module of the energy difference */
|
||||
rate += fabs ((supply->priv->energy_old_timespec[i].tv_sec - now.tv_sec) *
|
||||
(energy - supply->priv->energy_old[i]));
|
||||
valid_values++;
|
||||
}
|
||||
|
||||
/* get the next element in the circular buffer */
|
||||
i = (i + 1) % UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH;
|
||||
} while (i != supply->priv->energy_old_first);
|
||||
|
||||
/* Check that at least 3 points were involved in computation */
|
||||
if (sum_x == 0.0f || valid_values < 3)
|
||||
return supply->priv->rate_old;
|
||||
|
||||
/* Compute the discharge per hour, and not per second */
|
||||
rate /= sum_x / SECONDS_PER_HOUR_F;
|
||||
|
||||
/* if the rate is zero, use the old rate. It will usually happens if no
|
||||
* data is in the buffer yet. If the rate is too high, i.e. more than,
|
||||
* 100W don't use it. */
|
||||
if (rate == 0.0f || rate > 100.0f)
|
||||
return supply->priv->rate_old;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_get_string:
|
||||
**/
|
||||
|
|
@ -318,83 +163,6 @@ out:
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_get_design_voltage:
|
||||
**/
|
||||
static gdouble
|
||||
up_device_supply_get_design_voltage (UpDeviceSupply *device,
|
||||
GUdevDevice *native)
|
||||
{
|
||||
gdouble voltage;
|
||||
gchar *device_type = NULL;
|
||||
|
||||
/* design maximum */
|
||||
voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_max_design") / 1000000.0;
|
||||
if (voltage > 1.00f) {
|
||||
g_debug ("using max design voltage");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* design minimum */
|
||||
voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_min_design") / 1000000.0;
|
||||
if (voltage > 1.00f) {
|
||||
g_debug ("using min design voltage");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* current voltage */
|
||||
voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_present") / 1000000.0;
|
||||
if (voltage > 1.00f) {
|
||||
g_debug ("using present voltage");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* current voltage, alternate form */
|
||||
voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_now") / 1000000.0;
|
||||
if (voltage > 1.00f) {
|
||||
g_debug ("using present voltage (alternate)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* is this a USB device? */
|
||||
device_type = up_device_supply_get_string (native, "type");
|
||||
if (device_type != NULL && g_ascii_strcasecmp (device_type, "USB") == 0) {
|
||||
g_debug ("USB device, so assuming 5v");
|
||||
voltage = 5.0f;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* no valid value found; display a warning the first time for each
|
||||
* device */
|
||||
if (!device->priv->shown_invalid_voltage_warning) {
|
||||
device->priv->shown_invalid_voltage_warning = TRUE;
|
||||
g_warning ("no valid voltage value found for device %s, assuming 10V",
|
||||
g_udev_device_get_sysfs_path (native));
|
||||
}
|
||||
/* completely guess, to avoid getting zero values */
|
||||
g_debug ("no voltage values for device %s, using 10V as approximation",
|
||||
g_udev_device_get_sysfs_path (native));
|
||||
voltage = 10.0f;
|
||||
out:
|
||||
g_free (device_type);
|
||||
return voltage;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
up_device_supply_units_changed (UpDeviceSupply *supply,
|
||||
GUdevDevice *native)
|
||||
{
|
||||
if (supply->priv->coldplug_units == UP_DEVICE_SUPPLY_COLDPLUG_UNITS_CHARGE)
|
||||
if (g_udev_device_has_sysfs_attr_uncached (native, "charge_now") ||
|
||||
g_udev_device_has_sysfs_attr_uncached (native, "charge_avg"))
|
||||
return FALSE;
|
||||
if (supply->priv->coldplug_units == UP_DEVICE_SUPPLY_COLDPLUG_UNITS_ENERGY)
|
||||
if (g_udev_device_has_sysfs_attr_uncached (native, "energy_now") ||
|
||||
g_udev_device_has_sysfs_attr_uncached (native, "energy_avg"))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UpDeviceState
|
||||
up_device_supply_get_state (GUdevDevice *native)
|
||||
{
|
||||
|
|
@ -481,283 +249,6 @@ sysfs_get_capacity_level (GUdevDevice *native,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
up_device_supply_refresh_battery (UpDeviceSupply *supply,
|
||||
UpRefreshReason reason)
|
||||
{
|
||||
gchar *technology_native = NULL;
|
||||
gdouble voltage_design;
|
||||
UpDeviceState old_state;
|
||||
UpDeviceState state;
|
||||
UpDevice *device = UP_DEVICE (supply);
|
||||
GUdevDevice *native;
|
||||
gboolean is_present;
|
||||
gdouble energy;
|
||||
gdouble energy_full;
|
||||
gdouble energy_full_design;
|
||||
gdouble energy_rate;
|
||||
gdouble capacity = 100.0f;
|
||||
gdouble percentage = 0.0f;
|
||||
gdouble voltage;
|
||||
gint64 time_to_empty;
|
||||
gint64 time_to_full;
|
||||
gdouble temp;
|
||||
int charge_cycles = -1;
|
||||
gchar *manufacturer = NULL;
|
||||
gchar *model_name = NULL;
|
||||
gchar *serial_number = NULL;
|
||||
guint i;
|
||||
|
||||
native = G_UDEV_DEVICE (up_device_get_native (device));
|
||||
|
||||
/* have we just been removed? */
|
||||
if (g_udev_device_has_sysfs_attr_uncached (native, "present")) {
|
||||
is_present = g_udev_device_get_sysfs_attr_as_boolean_uncached (native, "present");
|
||||
} else {
|
||||
/* when no present property exists, handle as present */
|
||||
is_present = TRUE;
|
||||
}
|
||||
g_object_set (device, "is-present", is_present, NULL);
|
||||
if (!is_present) {
|
||||
up_device_supply_reset_values (supply);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get the current charge */
|
||||
energy = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_now") / 1000000.0;
|
||||
if (energy < 0.01)
|
||||
energy = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_avg") / 1000000.0;
|
||||
|
||||
/* used to convert A to W later */
|
||||
voltage_design = up_device_supply_get_design_voltage (supply, native);
|
||||
|
||||
/* initial values */
|
||||
if (!supply->priv->has_coldplug_values ||
|
||||
up_device_supply_units_changed (supply, native)) {
|
||||
|
||||
/* the ACPI spec is bad at defining battery type constants */
|
||||
technology_native = up_device_supply_get_string (native, "technology");
|
||||
g_object_set (device, "technology", up_convert_device_technology (technology_native), NULL);
|
||||
|
||||
/* get values which may be blank */
|
||||
manufacturer = up_device_supply_get_string (native, "manufacturer");
|
||||
model_name = up_device_supply_get_string (native, "model_name");
|
||||
serial_number = up_device_supply_get_string (native, "serial_number");
|
||||
|
||||
/* some vendors fill this with binary garbage */
|
||||
up_make_safe_string (manufacturer);
|
||||
up_make_safe_string (model_name);
|
||||
up_make_safe_string (serial_number);
|
||||
|
||||
g_object_set (device,
|
||||
"vendor", manufacturer,
|
||||
"model", model_name,
|
||||
"serial", serial_number,
|
||||
"is-rechargeable", TRUE, /* assume true for laptops */
|
||||
"has-history", TRUE,
|
||||
"has-statistics", TRUE,
|
||||
NULL);
|
||||
|
||||
/* these don't change at runtime */
|
||||
energy_full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_full") / 1000000.0;
|
||||
energy_full_design = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_full_design") / 1000000.0;
|
||||
|
||||
/* convert charge to energy */
|
||||
if (energy_full < 0.01) {
|
||||
energy_full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full") / 1000000.0;
|
||||
energy_full_design = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full_design") / 1000000.0;
|
||||
energy_full *= voltage_design;
|
||||
energy_full_design *= voltage_design;
|
||||
supply->priv->coldplug_units = UP_DEVICE_SUPPLY_COLDPLUG_UNITS_CHARGE;
|
||||
}
|
||||
|
||||
/* the last full should not be bigger than the design */
|
||||
if (energy_full > energy_full_design)
|
||||
g_warning ("energy_full (%f) is greater than energy_full_design (%f)",
|
||||
energy_full, energy_full_design);
|
||||
|
||||
/* some systems don't have this */
|
||||
if (energy_full < 0.01 && energy_full_design > 0.01) {
|
||||
g_warning ("correcting energy_full (%f) using energy_full_design (%f)",
|
||||
energy_full, energy_full_design);
|
||||
energy_full = energy_full_design;
|
||||
}
|
||||
|
||||
/* calculate how broken our battery is */
|
||||
if (energy_full > 0) {
|
||||
capacity = (energy_full / energy_full_design) * 100.0f;
|
||||
if (capacity < 0)
|
||||
capacity = 0.0;
|
||||
if (capacity > 100.0)
|
||||
capacity = 100.0;
|
||||
}
|
||||
g_object_set (device, "capacity", capacity, NULL);
|
||||
|
||||
/* we only coldplug once, as these values will never change */
|
||||
supply->priv->has_coldplug_values = TRUE;
|
||||
} else {
|
||||
/* get the old full */
|
||||
g_object_get (device,
|
||||
"energy-full", &energy_full,
|
||||
"energy-full-design", &energy_full_design,
|
||||
NULL);
|
||||
}
|
||||
|
||||
state = up_device_supply_get_state (native);
|
||||
|
||||
/* this is the new value in uW */
|
||||
if (g_udev_device_has_sysfs_attr (native, "power_now")) {
|
||||
energy_rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "power_now") / 1000000.0);
|
||||
} else {
|
||||
gdouble charge_full;
|
||||
|
||||
/* convert charge to energy */
|
||||
if (energy < 0.01) {
|
||||
energy = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_now") / 1000000.0;
|
||||
if (energy < 0.01)
|
||||
energy = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_avg") / 1000000.0;
|
||||
energy *= voltage_design;
|
||||
}
|
||||
|
||||
charge_full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full") / 1000000.0;
|
||||
if (charge_full < 0.01)
|
||||
charge_full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full_design") / 1000000.0;
|
||||
|
||||
/* If charge_full exists, then current_now is always reported in uA.
|
||||
* In the legacy case, where energy only units exist, and power_now isn't present
|
||||
* current_now is power in uW. */
|
||||
energy_rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "current_now") / 1000000.0);
|
||||
if (charge_full != 0)
|
||||
energy_rate *= voltage_design;
|
||||
}
|
||||
|
||||
/* some batteries don't update last_full attribute */
|
||||
if (energy > energy_full) {
|
||||
g_warning ("energy %f bigger than full %f", energy, energy_full);
|
||||
energy_full = energy;
|
||||
}
|
||||
|
||||
/* present voltage */
|
||||
voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_now") / 1000000.0;
|
||||
if (voltage < 0.01)
|
||||
voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_avg") / 1000000.0;
|
||||
|
||||
/* ACPI gives out the special 'Ones' value for rate when it's unable
|
||||
* to calculate the true rate. We should set the rate zero, and wait
|
||||
* for the BIOS to stabilise. */
|
||||
if (energy_rate == 0xffff)
|
||||
energy_rate = 0;
|
||||
|
||||
/* Ensure less than 300W, above the 240W possible with USB Power Delivery */
|
||||
if (energy_rate > 300)
|
||||
energy_rate = 0;
|
||||
|
||||
/* the hardware reporting failed -- try to calculate this */
|
||||
if (energy_rate < 0.01)
|
||||
energy_rate = up_device_supply_calculate_rate (supply, energy);
|
||||
|
||||
/* get a precise percentage */
|
||||
if (!supply->priv->ignore_system_percentage &&
|
||||
g_udev_device_has_sysfs_attr_uncached (native, "capacity")) {
|
||||
percentage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "capacity");
|
||||
percentage = CLAMP(percentage, 0.0f, 100.0f);
|
||||
/* for devices which provide capacity, but not {energy,charge}_now */
|
||||
if (energy < 0.1f && energy_full > 0.0f)
|
||||
energy = energy_full * percentage / 100;
|
||||
} else if (energy_full > 0.0f) {
|
||||
percentage = 100.0 * energy / energy_full;
|
||||
percentage = CLAMP(percentage, 0.0f, 100.0f);
|
||||
}
|
||||
|
||||
/* Some devices report "Not charging" when the battery is full and AC
|
||||
* power is connected. In this situation we should report fully-charged
|
||||
* instead of pending-charge. */
|
||||
if (state == UP_DEVICE_STATE_PENDING_CHARGE && percentage >= UP_FULLY_CHARGED_THRESHOLD)
|
||||
state = UP_DEVICE_STATE_FULLY_CHARGED;
|
||||
|
||||
/* if empty, and BIOS does not know what to do */
|
||||
if (state == UP_DEVICE_STATE_UNKNOWN && percentage < 1) {
|
||||
g_warning ("Setting %s state empty as unknown and very low",
|
||||
g_udev_device_get_sysfs_path (native));
|
||||
state = UP_DEVICE_STATE_EMPTY;
|
||||
}
|
||||
|
||||
/* some batteries give out massive rate values when nearly empty */
|
||||
if (energy < 0.1f)
|
||||
energy_rate = 0.0f;
|
||||
|
||||
/* calculate a quick and dirty time remaining value */
|
||||
time_to_empty = 0;
|
||||
time_to_full = 0;
|
||||
if (energy_rate > 0) {
|
||||
if (state == UP_DEVICE_STATE_DISCHARGING)
|
||||
time_to_empty = 3600 * (energy / energy_rate);
|
||||
else if (state == UP_DEVICE_STATE_CHARGING)
|
||||
time_to_full = 3600 * ((energy_full - energy) / energy_rate);
|
||||
/* TODO: need to factor in battery charge metrics */
|
||||
}
|
||||
|
||||
/* check the remaining time is under a set limit, to deal with broken
|
||||
primary batteries rate */
|
||||
if (time_to_empty > (240 * 60 * 60)) /* ten days for discharging */
|
||||
time_to_empty = 0;
|
||||
if (time_to_full > (20 * 60 * 60)) /* 20 hours for charging */
|
||||
time_to_full = 0;
|
||||
|
||||
/* get temperature */
|
||||
temp = g_udev_device_get_sysfs_attr_as_double_uncached (native, "temp") / 10.0;
|
||||
|
||||
/* charge_cycles is -1 if:
|
||||
* cycle_count is -1 (unknown)
|
||||
* cycle_count is 0 (shouldn't be used by conforming implementations)
|
||||
* cycle_count is absent (unsupported) */
|
||||
if (g_udev_device_has_sysfs_attr_uncached (native, "cycle_count")) {
|
||||
charge_cycles = g_udev_device_get_sysfs_attr_as_int_uncached (native, "cycle_count");
|
||||
if (charge_cycles == 0)
|
||||
charge_cycles = -1;
|
||||
}
|
||||
|
||||
/* check if the energy value has changed and, if that's the case,
|
||||
* store the new values in the buffer. */
|
||||
if (up_device_supply_push_new_energy (supply, energy))
|
||||
supply->priv->rate_old = energy_rate;
|
||||
|
||||
/* we changed state */
|
||||
g_object_get (device, "state", &old_state, NULL);
|
||||
if (old_state != state) {
|
||||
for (i = 0; i < UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH; ++i) {
|
||||
supply->priv->energy_old[i] = 0.0f;
|
||||
supply->priv->energy_old_timespec[i].tv_sec = 0;
|
||||
|
||||
}
|
||||
supply->priv->energy_old_first = 0;
|
||||
}
|
||||
|
||||
g_object_set (device,
|
||||
"energy", energy,
|
||||
"energy-full", energy_full,
|
||||
"energy-full-design", energy_full_design,
|
||||
"energy-rate", energy_rate,
|
||||
"percentage", percentage,
|
||||
"state", state,
|
||||
"voltage", voltage,
|
||||
"time-to-empty", time_to_empty,
|
||||
"time-to-full", time_to_full,
|
||||
"temperature", temp,
|
||||
"charge-cycles", charge_cycles,
|
||||
NULL);
|
||||
|
||||
/* Setup unknown poll again if needed */
|
||||
up_device_supply_update_poll_frequency (device, state, reason);
|
||||
|
||||
out:
|
||||
g_free (technology_native);
|
||||
g_free (manufacturer);
|
||||
g_free (model_name);
|
||||
g_free (serial_number);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
up_device_supply_refresh_device (UpDeviceSupply *supply,
|
||||
UpRefreshReason reason)
|
||||
|
|
@ -1026,71 +517,28 @@ up_device_supply_coldplug (UpDevice *device)
|
|||
"power-supply", is_power_supply,
|
||||
NULL);
|
||||
|
||||
if (type != UP_DEVICE_KIND_LINE_POWER &&
|
||||
type != UP_DEVICE_KIND_BATTERY)
|
||||
g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL);
|
||||
else if (type == UP_DEVICE_KIND_BATTERY &&
|
||||
(!supply->priv->disable_battery_poll || !is_power_supply))
|
||||
/* Handled by separate battery class */
|
||||
if (is_power_supply)
|
||||
g_assert (type == UP_DEVICE_KIND_LINE_POWER);
|
||||
|
||||
if (type != UP_DEVICE_KIND_LINE_POWER)
|
||||
g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
up_device_supply_update_poll_frequency (UpDevice *device,
|
||||
UpDeviceState state,
|
||||
UpRefreshReason reason)
|
||||
{
|
||||
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device);
|
||||
|
||||
if (supply->priv->disable_battery_poll)
|
||||
return;
|
||||
|
||||
/* We start fast-polling if the reason to update was not a normal POLL
|
||||
* and one of the following holds true:
|
||||
* 1. The current stat is unknown; we hope that this is transient
|
||||
* and re-poll.
|
||||
* 2. A change occured on a line power supply. This likely means that
|
||||
* batteries switch between charging/discharging which does not
|
||||
* always result in a separate uevent.
|
||||
*
|
||||
* For simplicity, we do the fast polling for a specific period of time.
|
||||
* If the reason to do fast-polling was an unknown state, then it would
|
||||
* also be reasonable to stop as soon as we got a proper state.
|
||||
*/
|
||||
if (reason != UP_REFRESH_POLL &&
|
||||
(state == UP_DEVICE_STATE_UNKNOWN ||
|
||||
reason == UP_REFRESH_LINE_POWER)) {
|
||||
g_debug ("unknown_poll: setting up fast re-poll");
|
||||
g_object_set (device, "poll-timeout", UP_DAEMON_UNKNOWN_TIMEOUT, NULL);
|
||||
supply->priv->fast_repoll_until = g_get_monotonic_time () + UP_DAEMON_UNKNOWN_POLL_TIME * G_USEC_PER_SEC;
|
||||
|
||||
} else if (supply->priv->fast_repoll_until == 0) {
|
||||
/* Not fast-repolling, no need to check whether to stop */
|
||||
|
||||
} else if (supply->priv->fast_repoll_until < g_get_monotonic_time ()) {
|
||||
g_debug ("unknown_poll: stopping fast repoll (giving up)");
|
||||
supply->priv->fast_repoll_until = 0;
|
||||
g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
up_device_supply_refresh (UpDevice *device, UpRefreshReason reason)
|
||||
{
|
||||
gboolean updated;
|
||||
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device);
|
||||
UpDeviceKind type;
|
||||
gboolean is_power_supply = FALSE;
|
||||
|
||||
g_object_get (device,
|
||||
"type", &type,
|
||||
"power-supply", &is_power_supply,
|
||||
NULL);
|
||||
if (type == UP_DEVICE_KIND_LINE_POWER) {
|
||||
updated = up_device_supply_refresh_line_power (supply, reason);
|
||||
} else if (type == UP_DEVICE_KIND_BATTERY && is_power_supply) {
|
||||
updated = up_device_supply_refresh_battery (supply, reason);
|
||||
} else {
|
||||
updated = up_device_supply_refresh_device (supply, reason);
|
||||
}
|
||||
|
|
@ -1108,22 +556,9 @@ up_device_supply_refresh (UpDevice *device, UpRefreshReason reason)
|
|||
static void
|
||||
up_device_supply_init (UpDeviceSupply *supply)
|
||||
{
|
||||
UpConfig *config;
|
||||
|
||||
supply->priv = up_device_supply_get_instance_private (supply);
|
||||
|
||||
/* allocate the stats for the battery charging & discharging */
|
||||
supply->priv->energy_old = g_new (gdouble, UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH);
|
||||
supply->priv->energy_old_timespec = g_new (GTimeVal, UP_DEVICE_SUPPLY_ENERGY_OLD_LENGTH);
|
||||
|
||||
supply->priv->shown_invalid_voltage_warning = FALSE;
|
||||
|
||||
config = up_config_new ();
|
||||
/* Seems that we don't get change uevents from the
|
||||
* kernel on some BIOS types, but if polling
|
||||
* is disabled in the configuration, do nothing */
|
||||
supply->priv->disable_battery_poll = up_config_get_boolean (config, "NoPollBatteries");
|
||||
g_object_unref (config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1140,46 +575,9 @@ up_device_supply_finalize (GObject *object)
|
|||
supply = UP_DEVICE_SUPPLY (object);
|
||||
g_return_if_fail (supply->priv != NULL);
|
||||
|
||||
g_free (supply->priv->energy_old);
|
||||
g_free (supply->priv->energy_old_timespec);
|
||||
|
||||
G_OBJECT_CLASS (up_device_supply_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
up_device_supply_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_IGNORE_SYSTEM_PERCENTAGE:
|
||||
supply->priv->ignore_system_percentage = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
up_device_supply_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_IGNORE_SYSTEM_PERCENTAGE:
|
||||
g_value_set_flags (value, supply->priv->ignore_system_percentage);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_class_init:
|
||||
**/
|
||||
|
|
@ -1190,17 +588,9 @@ up_device_supply_class_init (UpDeviceSupplyClass *klass)
|
|||
UpDeviceClass *device_class = UP_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->finalize = up_device_supply_finalize;
|
||||
object_class->set_property = up_device_supply_set_property;
|
||||
object_class->get_property = up_device_supply_get_property;
|
||||
device_class->get_on_battery = up_device_supply_get_on_battery;
|
||||
|
||||
device_class->get_online = up_device_supply_get_online;
|
||||
device_class->coldplug = up_device_supply_coldplug;
|
||||
device_class->sibling_discovered = up_device_supply_sibling_discovered;
|
||||
device_class->refresh = up_device_supply_refresh;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_IGNORE_SYSTEM_PERCENTAGE,
|
||||
g_param_spec_boolean ("ignore-system-percentage",
|
||||
"Ignore system percentage",
|
||||
"Ignore system provided battery percentage",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "up-enumerator-udev.h"
|
||||
|
||||
#include "up-device-supply.h"
|
||||
#include "up-device-supply-battery.h"
|
||||
#include "up-device-hid.h"
|
||||
#include "up-device-wup.h"
|
||||
|
||||
|
|
@ -93,11 +94,20 @@ device_new (UpEnumeratorUdev *self, GUdevDevice *native)
|
|||
|
||||
subsys = g_udev_device_get_subsystem (native);
|
||||
if (g_strcmp0 (subsys, "power_supply") == 0) {
|
||||
return g_initable_new (UP_TYPE_DEVICE_SUPPLY, NULL, NULL,
|
||||
UpDevice *device;
|
||||
|
||||
device = g_initable_new (UP_TYPE_DEVICE_SUPPLY_BATTERY, NULL, NULL,
|
||||
"daemon", daemon,
|
||||
"native", native,
|
||||
"ignore-system-percentage", GPOINTER_TO_INT (is_macbook (NULL)),
|
||||
NULL);
|
||||
if (device)
|
||||
return device;
|
||||
|
||||
return g_initable_new (UP_TYPE_DEVICE_SUPPLY, NULL, NULL,
|
||||
"daemon", daemon,
|
||||
"native", native,
|
||||
NULL);
|
||||
|
||||
} else if (g_strcmp0 (subsys, "tty") == 0) {
|
||||
return g_initable_new (UP_TYPE_DEVICE_WUP, NULL, NULL,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue