mirror of
https://gitlab.freedesktop.org/upower/upower.git
synced 2026-05-05 14:38:05 +02:00
linux: Add new UpDeviceSupplyBattery class
This split the functionality found in UpDeviceSupply to handle batteries out and is based on the previously added UpDeviceBattery class.
This commit is contained in:
parent
d672eb1d90
commit
ed2d5a25b3
5 changed files with 381 additions and 1 deletions
|
|
@ -10,6 +10,8 @@ upshared += { 'linux': static_library('upshared',
|
|||
sources: [
|
||||
'up-device-supply.c',
|
||||
'up-device-supply.h',
|
||||
'up-device-supply-battery.c',
|
||||
'up-device-supply-battery.h',
|
||||
'up-device-hid.c',
|
||||
'up-device-hid.h',
|
||||
'up-device-wup.c',
|
||||
|
|
|
|||
343
src/linux/up-device-supply-battery.c
Normal file
343
src/linux/up-device-supply-battery.c
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
|
||||
* Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
#include "up-config.h"
|
||||
#include "up-common.h"
|
||||
#include "up-types.h"
|
||||
#include "up-constants.h"
|
||||
#include "up-device-supply-battery.h"
|
||||
|
||||
/* For up_device_supply_get_state */
|
||||
#include "up-device-supply.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_IGNORE_SYSTEM_PERCENTAGE
|
||||
};
|
||||
|
||||
struct _UpDeviceSupplyBattery
|
||||
{
|
||||
gboolean has_coldplug_values;
|
||||
gboolean coldplug_units;
|
||||
gdouble *energy_old;
|
||||
GTimeVal *energy_old_timespec;
|
||||
guint energy_old_first;
|
||||
gdouble rate_old;
|
||||
gboolean shown_invalid_voltage_warning;
|
||||
gboolean ignore_system_percentage;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (UpDeviceSupplyBattery, up_device_supply_battery, UP_TYPE_DEVICE_BATTERY)
|
||||
|
||||
static gdouble
|
||||
up_device_supply_battery_get_design_voltage (UpDeviceSupplyBattery *self,
|
||||
GUdevDevice *native)
|
||||
{
|
||||
gdouble voltage;
|
||||
const 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");
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/* 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");
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/* 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");
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/* 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)");
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/* is this a USB device? */
|
||||
device_type = g_udev_device_get_sysfs_attr (native, "type");
|
||||
if (device_type != NULL && g_ascii_strcasecmp (device_type, "USB") == 0) {
|
||||
g_debug ("USB device, so assuming 5v");
|
||||
voltage = 5.0f;
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/* no valid value found; display a warning the first time for each
|
||||
* device */
|
||||
if (!self->shown_invalid_voltage_warning) {
|
||||
self->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;
|
||||
|
||||
return voltage;
|
||||
}
|
||||
|
||||
static char*
|
||||
get_sysfs_attr_uncached (GUdevDevice *native, const gchar *key)
|
||||
{
|
||||
g_autofree char *value = NULL;
|
||||
|
||||
/* get value, and strip to remove spaces */
|
||||
value = g_strdup (g_udev_device_get_sysfs_attr_uncached (native, key));
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
g_strstrip (value);
|
||||
if (value[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer (&value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
up_device_supply_battery_refresh (UpDevice *device,
|
||||
UpRefreshReason reason)
|
||||
{
|
||||
UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (device);
|
||||
UpDeviceBattery *battery = UP_DEVICE_BATTERY (device);
|
||||
GUdevDevice *native;
|
||||
UpBatteryInfo info = { 0 };
|
||||
UpBatteryValues values = { 0 };
|
||||
|
||||
native = G_UDEV_DEVICE (up_device_get_native (device));
|
||||
|
||||
/*
|
||||
* Reload battery information.
|
||||
* NOTE: If we assume that a udev event is guaranteed to happen, then
|
||||
* we can restrict this to updates other than UP_REFRESH_POLL.
|
||||
* NOTE: Only energy.full and cycle_count can change for a battery.
|
||||
*/
|
||||
info.present = g_udev_device_get_sysfs_attr_as_boolean_uncached (native, "present");
|
||||
if (!info.present) {
|
||||
up_device_battery_update_info (battery, &info);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
info.vendor = up_make_safe_string (get_sysfs_attr_uncached (native, "manufacturer"));
|
||||
info.model = up_make_safe_string (get_sysfs_attr_uncached (native, "model_name"));
|
||||
info.serial = up_make_safe_string (get_sysfs_attr_uncached (native, "serial_number"));
|
||||
|
||||
info.voltage_design = up_device_supply_battery_get_design_voltage (self, native);
|
||||
info.charge_cycles = g_udev_device_get_sysfs_attr_as_int_uncached (native, "cycle_count");
|
||||
|
||||
info.units = UP_BATTERY_UNIT_ENERGY;
|
||||
info.energy.full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_full") / 1000000.0;
|
||||
info.energy.design = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_full_design") / 1000000.0;
|
||||
|
||||
/* Assume we couldn't read anything if energy.full is extremely small */
|
||||
if (info.energy.full < 0.01) {
|
||||
info.units = UP_BATTERY_UNIT_CHARGE;
|
||||
info.energy.full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full") / 1000000.0;
|
||||
info.energy.design = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full_design") / 1000000.0;
|
||||
}
|
||||
info.technology = up_convert_device_technology (get_sysfs_attr_uncached (native, "technology"));
|
||||
|
||||
/* NOTE: We used to warn about full > design, but really that is prefectly fine to happen. */
|
||||
|
||||
/* Update the battery information (will only fire events for actual changes) */
|
||||
up_device_battery_update_info (battery, &info);
|
||||
|
||||
/*
|
||||
* Load runtime information.
|
||||
* NOTE: If we assume that a udev event is guaranteed to happen, then
|
||||
* we can restrict this to updates other than UP_REFRESH_POLL.
|
||||
*/
|
||||
values.units = info.units;
|
||||
|
||||
values.voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_now") / 1000000.0;
|
||||
if (values.voltage < 0.01)
|
||||
values.voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_avg") / 1000000.0;
|
||||
|
||||
|
||||
switch (values.units) {
|
||||
case UP_BATTERY_UNIT_CHARGE:
|
||||
/* QUIRK:
|
||||
* Some batteries (Nexus 7?) may report a separate energy_now.
|
||||
* This appears to be more accurate (as it takes into account
|
||||
* the dropping voltage). However, we ignore this here for
|
||||
* consistency (but we used to read it in the past).
|
||||
*
|
||||
* See https://bugs.freedesktop.org/show_bug.cgi?id=60104#c2
|
||||
* whichs reports energy_now of 15.05 Wh while our calculation
|
||||
* will be ~16.4Wh by multiplying charge with voltage).
|
||||
*/
|
||||
values.energy.rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "current_now") / 1000000.0);
|
||||
values.energy.cur = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_now") / 1000000.0);
|
||||
break;
|
||||
case UP_BATTERY_UNIT_ENERGY:
|
||||
values.energy.rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "power_now") / 1000000.0);
|
||||
values.energy.cur = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_now") / 1000000.0);
|
||||
if (values.energy.cur < 0.01)
|
||||
values.energy.cur = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_avg") / 1000000.0;
|
||||
|
||||
/* Legacy case: If we have energy units but no power_now, then current_now is in uW. */
|
||||
if (values.energy.rate < 0)
|
||||
values.energy.rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "current_now") / 1000000.0);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* NOTE:
|
||||
* The old code tried to special case the 0xffff ACPI value of the energy rate.
|
||||
* That doesn't really make any sense after doing the floating point math.
|
||||
*/
|
||||
|
||||
if (!self->ignore_system_percentage) {
|
||||
values.percentage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "capacity");
|
||||
values.percentage = CLAMP(values.percentage, 0.0f, 100.0f);
|
||||
}
|
||||
|
||||
values.state = up_device_supply_get_state (native);
|
||||
|
||||
values.temperature = g_udev_device_get_sysfs_attr_as_double_uncached (native, "temp") / 10.0;
|
||||
|
||||
up_device_battery_report (battery, &values, reason);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* up_device_supply_coldplug:
|
||||
*
|
||||
* Return %TRUE on success, %FALSE if we failed to get data and should be removed
|
||||
**/
|
||||
static gboolean
|
||||
up_device_supply_coldplug (UpDevice *device)
|
||||
{
|
||||
GUdevDevice *native;
|
||||
const gchar *native_path;
|
||||
const gchar *scope;
|
||||
const gchar *type;
|
||||
|
||||
/* detect what kind of device we are */
|
||||
native = G_UDEV_DEVICE (up_device_get_native (device));
|
||||
native_path = g_udev_device_get_sysfs_path (native);
|
||||
if (native_path == NULL) {
|
||||
g_warning ("could not get native path for %p", device);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* try to work out if the device is powering the system */
|
||||
scope = g_udev_device_get_sysfs_attr (native, "scope");
|
||||
if (scope != NULL && g_ascii_strcasecmp (scope, "device") == 0)
|
||||
return FALSE;
|
||||
|
||||
/* Complain about a non-system scope, while accepting no scope information */
|
||||
if (scope != NULL && g_ascii_strcasecmp (scope, "system") != 0)
|
||||
g_warning ("Assuming system scope even though scope is %s", scope);
|
||||
|
||||
/* type should be a battery, but also accept unknown if "online" does not exist */
|
||||
type = g_udev_device_get_sysfs_attr (native, "type");
|
||||
if (!type || g_ascii_strcasecmp (type, "battery") != 0) {
|
||||
if (g_udev_device_has_sysfs_attr (native, "online"))
|
||||
return FALSE;
|
||||
|
||||
/* this is a good guess as UPS and CSR are not in the kernel */
|
||||
g_warning ("Assuming battery as sysfs attribute 'type' is %s", type);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
up_device_supply_battery_init (UpDeviceSupplyBattery *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
up_device_supply_battery_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_IGNORE_SYSTEM_PERCENTAGE:
|
||||
self->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_battery_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_IGNORE_SYSTEM_PERCENTAGE:
|
||||
g_value_set_flags (value, self->ignore_system_percentage);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
up_device_supply_battery_class_init (UpDeviceSupplyBatteryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
UpDeviceClass *device_class = UP_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->set_property = up_device_supply_battery_set_property;
|
||||
object_class->get_property = up_device_supply_battery_get_property;
|
||||
device_class->coldplug = up_device_supply_coldplug;
|
||||
device_class->refresh = up_device_supply_battery_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));
|
||||
}
|
||||
33
src/linux/up-device-supply-battery.h
Normal file
33
src/linux/up-device-supply-battery.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2022 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "up-device-battery.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define MAX_DISCHARGE_RATE 300
|
||||
|
||||
#define UP_TYPE_DEVICE_SUPPLY_BATTERY (up_device_supply_battery_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (UpDeviceSupplyBattery, up_device_supply_battery, UP, DEVICE_SUPPLY_BATTERY, UpDeviceBattery)
|
||||
|
||||
G_END_DECLS
|
||||
|
|
@ -395,7 +395,7 @@ up_device_supply_units_changed (UpDeviceSupply *supply,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static UpDeviceState
|
||||
UpDeviceState
|
||||
up_device_supply_get_state (GUdevDevice *native)
|
||||
{
|
||||
UpDeviceState state;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ typedef struct
|
|||
|
||||
GType up_device_supply_get_type (void);
|
||||
|
||||
UpDeviceState up_device_supply_get_state (GUdevDevice *native);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __UP_DEVICE_SUPPLY_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue