[gnome-battery-bench] Power supply: basic voltage & energy setup code



commit f7da26f059cc2f9ddddb42575689e080194de6e9
Author: Christian Kellner <gicmo gnome org>
Date:   Fri Mar 17 16:14:32 2017 +0100

    Power supply: basic voltage & energy setup code

 src/power-supply.c |  183 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 178 insertions(+), 5 deletions(-)
---
diff --git a/src/power-supply.c b/src/power-supply.c
index 018c57d..5ded60a 100644
--- a/src/power-supply.c
+++ b/src/power-supply.c
@@ -3,6 +3,10 @@
 #include <glib.h>
 #include <gudev/gudev.h>
 
+#define _ISOC99_SOURCE //for NAN
+#include <math.h>
+#include <limits.h>
+
 #include "power-supply.h"
 
 struct _GbbBattery {
@@ -11,6 +15,13 @@ struct _GbbBattery {
     GUdevDevice *udevice;
     char *vendor;
     char *model;
+
+    double voltage_desgin;
+
+    double energy;
+    double energy_full;
+    double energy_full_design;
+    gboolean use_charge;
 };
 
 enum {
@@ -20,6 +31,12 @@ enum {
     PROP_VENDOR,
     PROP_MODEL,
 
+    PROP_VOLTAGE_DESIGN,
+
+    PROP_ENERGY,
+    PROP_ENERGY_FULL,
+    PROP_ENERGY_FULL_DESIGN,
+
     PROP_BAT_LAST
 };
 
@@ -27,6 +44,15 @@ static GParamSpec *battery_props[PROP_BAT_LAST] = { NULL, };
 
 G_DEFINE_TYPE(GbbBattery, gbb_battery, G_TYPE_OBJECT);
 
+
+static char *   sysfs_read_string_cached             (GUdevDevice *device,
+                                               const char  *name);
+static double   sysfs_read_double_scaled      (GUdevDevice *device,
+                                               const char  *name);
+
+static void     voltage_design_initialize     (GbbBattery *battery);
+static void     energy_design_initialize      (GbbBattery *battery);
+
 static void
 gbb_battery_finalize(GObject *obj)
 {
@@ -60,6 +86,22 @@ gbb_battery_get_property(GObject    *object,
     case PROP_MODEL:
         g_value_set_string(value, bat->model);
         break;
+
+    case PROP_VOLTAGE_DESIGN:
+        g_value_set_double(value, bat->voltage_desgin);
+        break;
+
+    case PROP_ENERGY:
+        g_value_set_double(value, bat->energy);
+        break;
+
+    case PROP_ENERGY_FULL:
+        g_value_set_double(value, bat->energy_full);
+        break;
+
+    case PROP_ENERGY_FULL_DESIGN:
+        g_value_set_double(value, bat->energy_full_design);
+        break;
     }
 }
 
@@ -86,13 +128,12 @@ gbb_battery_constructed(GObject *obj)
 {
     GbbBattery *bat = GBB_BATTERY(obj);
     GUdevDevice *device = bat->udevice;
-    const gchar *value;
 
-    value = g_udev_device_get_sysfs_attr(device, "manufacturer");
-    bat->vendor = g_strdup(value);
+    bat->vendor = sysfs_read_string_cached(device, "manufacturer");
+    bat->model = sysfs_read_string_cached(device, "model_name");
 
-    value = g_udev_device_get_sysfs_attr(device, "model_name");
-    bat->model = g_strdup(value);
+    voltage_design_initialize(bat);
+    energy_design_initialize(bat);
 
     G_OBJECT_CLASS(gbb_battery_parent_class)->constructed(obj);
 }
@@ -134,12 +175,144 @@ gbb_battery_class_init(GbbBatteryClass *klass)
                             G_PARAM_READABLE |
                             G_PARAM_STATIC_NAME);
 
+    battery_props[PROP_VOLTAGE_DESIGN] =
+        g_param_spec_double("voltage-design",
+                            NULL, NULL,
+                            0, G_MAXDOUBLE, 0,
+                            G_PARAM_READABLE |
+                            G_PARAM_STATIC_NAME);
+
+    battery_props[PROP_ENERGY] =
+        g_param_spec_double("energy",
+                            NULL, NULL,
+                            0, G_MAXDOUBLE, 0,
+                            G_PARAM_READABLE |
+                            G_PARAM_STATIC_NAME);
+
+    battery_props[PROP_ENERGY_FULL] =
+        g_param_spec_double("energy-full",
+                            NULL, NULL,
+                            0, G_MAXDOUBLE, 0,
+                            G_PARAM_READABLE |
+                            G_PARAM_STATIC_NAME);
+
+    battery_props[PROP_ENERGY_FULL_DESIGN] =
+        g_param_spec_double("energy-full-design",
+                            NULL, NULL,
+                            0, G_MAXDOUBLE, 0,
+                            G_PARAM_READABLE |
+                            G_PARAM_STATIC_NAME);
+
     g_object_class_install_properties(gobject_class,
                                       PROP_BAT_LAST,
                                       battery_props);
 }
 
 
+static char *
+sysfs_read_string_cached(GUdevDevice *device, const char *name)
+{
+    const char *value;
+
+    value = g_udev_device_get_sysfs_attr(device, name);
+    if (value == NULL) {
+        value = "Unknown";
+    }
+
+    return g_strdup(value);
+}
+
+static double
+sysfs_read_double_scaled(GUdevDevice *device, const char *name)
+{
+    g_autofree char *buffer = NULL;
+    char filename[PATH_MAX];
+    const char *path;
+    guint64 value;
+    double dv;
+    gboolean ok;
+    char *end;
+
+    path = g_udev_device_get_sysfs_path(device);
+
+    g_snprintf(filename, sizeof(filename), "%s/%s", path, name);
+    ok = g_file_get_contents(filename, &buffer, NULL, NULL);
+    if (!ok) {
+        return NAN;
+    }
+
+    value = g_ascii_strtoull(buffer, &end, 10);
+    if (end != buffer) {
+        dv = value / 1000000.;
+    } else {
+        dv = NAN;
+    }
+
+    return dv;
+}
+
+static const char *voltage_sources[] = {
+    "voltage_min_design",
+    "voltage_max_design",
+    "voltage_present",
+    "voltage_now",
+    NULL
+};
+
+static void
+voltage_design_initialize (GbbBattery *bat)
+{
+    const char **source;
+
+    for (source = voltage_sources; *source != NULL; source++) {
+        const char *name = *source;
+        double val = sysfs_read_double_scaled(bat->udevice, name);
+
+        if (val > 1.0) {
+            g_debug("Using '%s' as design voltage", name);
+            bat->voltage_desgin = val;
+            return;
+        }
+    }
+
+    g_warning("Could not get design voltage, estimating 12V.");
+    bat->voltage_desgin = 12;
+}
+
+static void
+energy_design_initialize(GbbBattery *bat)
+{
+    GUdevDevice *dev = bat->udevice;
+    double val;
+
+    val = sysfs_read_double_scaled(dev, "energy_now");
+    if (val > 1.0f) {
+        val = sysfs_read_double_scaled(dev, "energy_full");
+        bat->energy_full = val;
+
+        val = sysfs_read_double_scaled(dev, "energy_full_design");
+        bat->energy_full_design = val;
+        return;
+    }
+
+    val = sysfs_read_double_scaled(dev, "charge_now");
+    if (val > 1.0f) {
+        const double voltage_design = bat->voltage_desgin;
+        val = sysfs_read_double_scaled(dev, "charge_full");
+        bat->energy_full = val * voltage_design;
+
+        val = sysfs_read_double_scaled(dev, "charge_full_design");
+        bat->energy_full_design = val * voltage_design;
+
+        bat->use_charge = TRUE;
+    }
+
+    if (bat->energy_full < 1.0f ||
+        bat->energy_full_design < 1.0f) {
+        /* We actually should report that and give up working at all */
+        g_warning("Could not get energy full (design) for battery");
+    }
+}
 
 GList *
 gbb_battery_discover()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]