All pastes #241211 Raw Edit

Unnamed

public text v1 · immutable
·published 2006-11-06 01:43 UTC
rendered paste body
diff --git a/hald/Makefile.am b/hald/Makefile.am
index 7201b1a..7e369f6 100644
--- a/hald/Makefile.am
+++ b/hald/Makefile.am
@@ -41,6 +41,7 @@ hald_SOURCES =                          
 	util.h				util.c				\
 	util_helper.h			util_helper.c			\
 	util_pm.h			util_pm.c			\
+	util_battery.h			util_battery.c			\
 	hald_runner.h			hald_runner.c			\
 	device.h			device.c			\
 	device_info.h			device_info.c			\
diff --git a/hald/linux/acpi.c b/hald/linux/acpi.c
index 2c59fbf..4dbecff 100644
--- a/hald/linux/acpi.c
+++ b/hald/linux/acpi.c
@@ -32,6 +32,7 @@ #include "../hald_dbus.h"
 #include "../logger.h"
 #include "../util.h"
 #include "../util_pm.h"
+#include "../util_battery.h"
 
 #include "osspec_linux.h"
 
@@ -77,27 +78,31 @@ ac_adapter_refresh_poll (HalDevice *d)
 	hal_util_set_bool_elem_from_file (d, "ac_adapter.present", path, "state", "state", 0, "on-line", FALSE);
 }
 
+/* architecture specific bits should try to populate:
+- current
+- last_full
+- is_charging
+- is_discharging
+- rate
+- voltage
+- last_full
+
+TODO: don't read the key twice from haldb
+TODO: only save the key if proc entry present
+ */
 static void
-battery_refresh_poll (HalDevice *d)
+battery_refresh_acpi (HalDevice *d, const char *path)
 {
-	const char *path;
-	const char *reporting_unit;
-	int reporting_current;
-	int reporting_lastfull;
-	int reporting_rate;
-	int normalised_current;
-	int normalised_lastfull;
-	int normalised_rate;
-	int design_voltage;
-	int voltage;
-	int remaining_time;
-	int remaining_percentage;
-	gboolean charging;
-	gboolean discharging;
+	HalBattery *bat;
 
-	path = hal_device_property_get_string (d, "linux.acpi_path");
-	if (path == NULL)
+	/* get battery object */
+	bat = util_battery_get_data (d);
+	if (bat == NULL) {
+		HAL_WARNING (("Battery object not found"));
 		return;
+	}
+
+	/* get data from proc, add it to the battery.reporting.* keys and copy to HalBattery struct */
 
 	hal_util_set_bool_elem_from_file (d, "battery.rechargeable.is_charging", path,
 					  "state", "charging state", 0, "charging", TRUE);
@@ -115,132 +120,42 @@ battery_refresh_poll (HalDevice *d)
 	if (!hal_util_set_int_elem_from_file (d, "battery.reporting.rate", path,
 					      "state", "present rate", 0, 10, TRUE))
 		hal_device_property_set_int (d, "battery.reporting.rate", 0);
+
 	/*
 	 * we'll need this if we need to convert mAh to mWh, but we should
 	 * also update it here anyway as the value will have changed
 	 */
 	hal_util_set_int_elem_from_file (d, "battery.voltage.current", path,
 					 "state", "present voltage", 0, 10, TRUE);
-	/* get all the data we know */
-	reporting_unit = hal_device_property_get_string (d,
-					"battery.reporting.unit");
-	reporting_current = hal_device_property_get_int (d,
+
+	/* get all the data we know (probably need to check for -1 also) */
+	bat->current = hal_device_property_get_int (d,
 					"battery.reporting.current");
-	reporting_lastfull = hal_device_property_get_int (d,
+	bat->last_full = hal_device_property_get_int (d,
 					"battery.reporting.last_full");
-	reporting_rate = hal_device_property_get_int (d,
+	bat->rate = hal_device_property_get_int (d,
 					"battery.reporting.rate");
+	bat->voltage = hal_device_property_get_int (d,
+					"battery.voltage.current");
 
-	/*
-	 * 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.
-	 *
-	 * full details here: http://bugzilla.gnome.org/show_bug.cgi?id=348201
-	 */
-	if (reporting_rate == 0xffff) {
-		reporting_rate = 0;
-	}
-
-	/*
-	 * We are converting the unknown units into mWh because of ACPI's nature
-	 * of not having a standard "energy" unit.
-	 *
-	 * full details here: http://bugzilla.gnome.org/show_bug.cgi?id=309944
-	 */
-	if (reporting_unit && strcmp (reporting_unit, "mAh") == 0) {
-		/* convert mAh to mWh by multiplying by voltage.  due to the
-		 * general wonkiness of ACPI implementations, this is a lot
-		 * harder than it should have to be...
-		 */
-
-		design_voltage = hal_device_property_get_int (d, "battery.voltage.design");
-		voltage = hal_device_property_get_int (d, "battery.voltage.current");
-
-		/* Just in case we don't get design voltage information, then
-		 * this will pretend that we have 1V.  This degrades our
-		 * ability to report accurate times on multi-battery systems
-		 * but will always prevent negative charge levels and allow
-		 * accurate reporting on single-battery systems.
-		 */
-		if (design_voltage <= 0)
-			design_voltage = 1000; /* mV */
-
-		/* If the current voltage is unknown, smaller than 50% of design voltage (fd.o #8593) 
-		 * or greater than design, then use design voltage.
-		 */
-		if (voltage < (design_voltage/2)  || voltage > design_voltage) {
-			HAL_DEBUG (("Current voltage is unknown, smaller than 50% or greater than design"));
-			voltage = design_voltage;
-		}
-
-		normalised_current = (reporting_current * voltage) / 1000;
-		normalised_lastfull = (reporting_lastfull * voltage) / 1000;
-		normalised_rate = (reporting_rate * voltage) / 1000;
-	} else {
-		/*
-		 * handle as if mWh (which don't need conversion), which is the most common case.
-		 */
-		normalised_current = reporting_current;
-		normalised_lastfull = reporting_lastfull;
-		normalised_rate = reporting_rate;
-	}
-
-	/*
-	 * Set the normalised keys.
-	 */
-	if (normalised_current < 0)
-		normalised_current = 0;
-	if (normalised_lastfull < 0)
-		normalised_lastfull = 0;
-	if (normalised_rate < 0)
-		normalised_rate = 0;
-
-	/*
-	 * Some laptops report a rate even when not charging or discharging.
-	 * If not charging and not discharging force rate to be zero.
-         *
-         * http://bugzilla.gnome.org/show_bug.cgi?id=323186
-	 */
-	charging = hal_device_property_get_bool (d, "battery.rechargeable.is_charging");
-	discharging = hal_device_property_get_bool (d, "battery.rechargeable.is_discharging");
+	bat->is_charging = hal_device_property_get_bool (d, "battery.rechargeable.is_charging");
+	bat->is_discharging = hal_device_property_get_bool (d, "battery.rechargeable.is_discharging");
+}
 
-	if (!charging && !discharging)
-		normalised_rate = 0;
+static void
+battery_refresh_poll (HalDevice *d)
+{
+	const char *path;
 
-	/*
-	 * Some laptops report current charge much larger than
-	 * full charge when at 100%.  Clamp back down to 100%.
-	 */
-	if (normalised_current > normalised_lastfull)
-	  	normalised_current = normalised_lastfull;
-
-	hal_device_property_set_int (d, "battery.charge_level.current", normalised_current);
-	hal_device_property_set_int (d, "battery.charge_level.last_full", normalised_lastfull);
-	hal_device_property_set_int (d, "battery.charge_level.rate", normalised_rate);
-
-	remaining_time = util_compute_time_remaining (
-		hal_device_get_udi (d), 
-		normalised_rate, normalised_current, normalised_lastfull,
-		hal_device_property_get_bool (d, "battery.rechargeable.is_discharging"),
-		hal_device_property_get_bool (d, "battery.rechargeable.is_charging"),
-		hal_device_property_get_bool (d, "battery.remaining_time.calculate_per_time"));
-	remaining_percentage = util_compute_percentage_charge (hal_device_get_udi (d), normalised_current, normalised_lastfull);
-	/*
-	 * Only set keys if no error (signified with negative return value)
-	 * Scrict checking is needed to ensure that the values presented by HAL
-	 * are 100% acurate.
-	 */
+	path = hal_device_property_get_string (d, "linux.acpi_path");
+	if (path == NULL)
+		return;
 
-	if (remaining_time > 0)
-		hal_device_property_set_int (d, "battery.remaining_time", remaining_time);
-	else
-		hal_device_property_remove (d, "battery.remaining_time");
+	/* do acpi specific bit */
+	battery_refresh_acpi (d, path);
 
-	if (remaining_percentage > 0)
-		hal_device_property_set_int (d, "battery.charge_level.percentage", remaining_percentage);
-	else
-		hal_device_property_remove (d, "battery.charge_level.percentage");
+	/* do generic bit */
+	util_battery_update_values (d);
 }
 
 /** Recalculates the battery.reporting.last_full key as this may drift
@@ -462,10 +377,10 @@ battery_refresh_add (HalDevice *d, const
 	int reporting_low;
 	int reporting_gran1;
 	int reporting_gran2;
-	int voltage_design;
-
-	const char *reporting_unit;
 	const char *technology;
+	const char *strunit;
+
+	HalBattery *bat;
 
 	hal_util_set_string_elem_from_file (d, "battery.vendor", path, "info",
 					    "OEM info", 0, TRUE);
@@ -488,15 +403,30 @@ battery_refresh_add (HalDevice *d, const
 	}
 
 	/*
+	 * Create the HAL class data if it does not already exist
+	 */
+	bat = util_battery_get_data (d);
+	if (bat == NULL) {
+		bat = g_new (HalBattery, 1);
+		g_object_set_data ((gpointer) d, "battery-object", bat);
+	}
+
+	/* get the common stuff and put into battery class data */
+	battery_refresh_acpi (d, path);
+
+	/*
 	 * we'll use the .reporting prefix as we don't know
 	 * if this data is energy (mWh) or unit enery (mAh)
 	 */
 	hal_util_set_string_elem_from_file (d, "battery.reporting.unit", path,
 					 "info", "design capacity", 1, TRUE);
-	hal_util_set_int_elem_from_file (d, "battery.reporting.last_full", path,
-					 "info", "last full capacity", 0, 10, TRUE);
+	strunit = hal_device_property_get_string (d,
+					"battery.reporting.unit");
+	util_battery_set_unit_from_string (bat, strunit);
+
 	hal_util_set_int_elem_from_file (d, "battery.reporting.design", path,
 					 "info", "design capacity", 0, 10, TRUE);
+
 	hal_util_set_int_elem_from_file (d, "battery.reporting.warning", path,
 					 "info", "design capacity warning", 0, 10, TRUE);
 	hal_util_set_int_elem_from_file (d, "battery.reporting.low", path,
@@ -518,31 +448,29 @@ battery_refresh_add (HalDevice *d, const
 	 * are not going to change.
 	 * We'll set the correct unit (or unknown) also.
 	 */
-	reporting_unit = hal_device_property_get_string (d, "battery.reporting.unit");
 	reporting_design = hal_device_property_get_int (d, "battery.reporting.design");
 	reporting_warning = hal_device_property_get_int (d, "battery.reporting.warning");
 	reporting_low = hal_device_property_get_int (d, "battery.reporting.low");
 	reporting_gran1 = hal_device_property_get_int (d, "battery.reporting.granularity_1");
 	reporting_gran2 = hal_device_property_get_int (d, "battery.reporting.granularity_2");
 
-	if (reporting_unit && strcmp (reporting_unit, "mAh") == 0) {
-		voltage_design = hal_device_property_get_int (d, "battery.voltage.design");
-	
-		/* If design voltage is unknown, use 1V. */
-		if (voltage_design <= 0)
-			voltage_design = 1000; /* mV */;
+	/* correct the voltage */
+	bat->design_voltage = hal_device_property_get_int (d, "battery.voltage.design");
+	util_battery_check_voltage (d, bat);
+
+	if (bat->unit == HAL_BATTERY_TYPE_MAH) {
 
-		/* scale by factor battery.voltage.design */
+		/* scale by voltage  */
 		hal_device_property_set_int (d, "battery.charge_level.design",
-			(reporting_design * voltage_design) / 1000);
+			(reporting_design * bat->voltage) / 1000);
 		hal_device_property_set_int (d, "battery.charge_level.warning",
-			(reporting_warning * voltage_design) / 1000);
+			(reporting_warning * bat->voltage) / 1000);
 		hal_device_property_set_int (d, "battery.charge_level.low",
-			(reporting_low * voltage_design) / 1000);
+			(reporting_low * bat->voltage) / 1000);
 		hal_device_property_set_int (d, "battery.charge_level.granularity_1",
-			(reporting_gran1 * voltage_design) / 1000);
+			(reporting_gran1 * bat->voltage) / 1000);
 		hal_device_property_set_int (d, "battery.charge_level.granularity_2",
-			(reporting_gran2 * voltage_design) / 1000);
+			(reporting_gran2 * bat->voltage) / 1000);
 
 		/* set unit */
 		hal_device_property_set_string (d, "battery.charge_level.unit", "mWh"); /* not mAh! */
@@ -558,7 +486,7 @@ battery_refresh_add (HalDevice *d, const
 		hal_device_property_set_int (d, "battery.charge_level.granularity_2", reporting_gran2);
 
 		/* set unit */
-		if (reporting_unit && strcmp (reporting_unit, "mWh") == 0) {
+		if (bat->unit == HAL_BATTERY_TYPE_MWH) {
 			hal_device_property_set_string (d, "battery.charge_level.unit", "mWh");
 		} else {
 			/* set "Unknown ACPI Unit" unit so we can debug */
diff --git a/hald/util_pm.c b/hald/util_pm.c
index 0bc62e8..e93554f 100644
--- a/hald/util_pm.c
+++ b/hald/util_pm.c
@@ -1,9 +1,9 @@
 /***************************************************************************
  * CVSID: $Id$
  *
- * utili_pm.c - Various Powermanagement related utilities
+ * util_pm.c - Various Powermanagement related utilities
  *
- * Copyright (C) 2005 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2005-2006 Richard Hughes <richard@hughsie.com>
  * Copyright (C) 2005 Danny Kukawka <danny.kukawka@web.de>
  *
  * Licensed under the Academic Free License version 2.1
@@ -36,9 +36,10 @@ #include "logger.h"
 
 #include "util_pm.h"
 
+/* depreciated; remove PMU and APM users */
 typedef struct {
 	int last_level;
-	int last_chargeRate;
+	int last_rate;
 	time_t last_time;
 } batteryInfo;
 
@@ -77,30 +78,32 @@ util_get_battery_technology (const char 
 	return "unknown";
 }
 
+
+/* BELOW ARE DEPRECIATED */
 /** Given all the required parameters, this function will return the percentage
  *  charge remaining. There are lots of checks here as ACPI is often broken.
  *
  *  @param  id                  Optional ID given to this battery. Unused at present.
- *  @param  chargeLevel         The current charge level of the battery (typically mWh)
- *  @param  chargeLastFull      The last "full" charge of the battery (typically mWh)
+ *  @param  current         The current charge level of the battery (typically mWh)
+ *  @param  last_full      The last "full" charge of the battery (typically mWh)
  *  @return                     Percentage, -1 if invalid
  */
 int 
 util_compute_percentage_charge (const char *id,
-			     int chargeLevel,
-			     int chargeLastFull)
+			     int current,
+			     int last_full)
 {
 	int percentage;
 	/* make sure we have chargelevel */
-	if (chargeLevel <= 0) {
-		HAL_WARNING (("chargeLevel %i, returning -1!", chargeLevel));
+	if (current <= 0) {
+		HAL_WARNING (("current %i, returning -1!", current));
 		return -1;
 	}
 	/* make sure not division by zero */
-	if (chargeLastFull > 0)
-		percentage = ((double) chargeLevel / (double) chargeLastFull) * 100;
+	if (last_full > 0)
+		percentage = ((double) current / (double) last_full) * 100;
 	else {
-		HAL_WARNING (("chargeLastFull %i, percentage returning -1!", chargeLastFull));
+		HAL_WARNING (("last_full %i, percentage returning -1!", last_full));
 		return -1;
 	}
 	/* Some bios's will report this higher than 100, limit it here */
@@ -121,41 +124,41 @@ util_compute_percentage_charge (const ch
  *  of seconds until empty (if discharging)
  *
  *  @param  id                  Optional ID given to this battery. Unused at present.
- *  @param  chargeRate          The "rate" (typically mW)
- *  @param  chargeLevel         The current charge level of the battery (typically mWh)
- *  @param  chargeLastFull      The last "full" charge of the battery (typically mWh)
- *  @param  isDischarging       If battery is discharging
- *  @param  isCharging          If battery is charging
- *  @param  guessChargeRate     If ignore chargeRate and guess them.
+ *  @param  rate          The "rate" (typically mW)
+ *  @param  current         The current charge level of the battery (typically mWh)
+ *  @param  last_full      The last "full" charge of the battery (typically mWh)
+ *  @param  is_discharging       If battery is discharging
+ *  @param  is_charging          If battery is charging
+ *  @param  guessChargeRate     If ignore rate and guess them.
  *  @return                     Number of seconds, or -1 if invalid
  */
 int 
 util_compute_time_remaining (const char *id,
-			     int chargeRate,
-			     int chargeLevel,
-			     int chargeLastFull,
-			     gboolean isDischarging,
-			     gboolean isCharging,
+			     int rate,
+			     int current,
+			     int last_full,
+			     gboolean is_discharging,
+			     gboolean is_charging,
 			     gboolean guessChargeRate)
 {
 	int remaining_time = 0;
 
 	/* should not get negative values */
-	if (chargeRate < 0 || chargeLevel < 0 || chargeLastFull < 0) {
-		HAL_WARNING (("chargeRate, chargeLevel or chargeLastFull < 0, returning -1"));
+	if (rate < 0 || current < 0 || last_full < 0) {
+		HAL_WARNING (("rate, current or last_full < 0, returning -1"));
 		return -1;
 	}
 	/* batteries cannot charge and discharge at the same time */
-	if (isDischarging && isCharging) {
-		HAL_WARNING (("isDischarging & isCharging TRUE, returning -1"));
+	if (is_discharging && is_charging) {
+		HAL_WARNING (("is_discharging & is_charging TRUE, returning -1"));
 		return -1;
 	}
 	/* 
 	 * Some laptops don't supply any rate info, but that's no reason for HAL not
-	 * to. We use the current and previous chargeLevel to estimate the rate.
+	 * to. We use the current and previous current to estimate the rate.
 	 * The info is stored in a GHashTable because there could be more than one battery.
 	 */
-	if (chargeRate == 0 || guessChargeRate) {
+	if (rate == 0 || guessChargeRate || 1) {
 		batteryInfo *battery_info;
 		time_t cur_time = time(NULL);
 
@@ -165,50 +168,52 @@ util_compute_time_remaining (const char 
 
 		if ((battery_info = g_hash_table_lookup(saved_battery_info, id))) {
 			/* check this to prevent division by zero */
-			if ((cur_time == battery_info->last_time) || (chargeLevel == battery_info->last_level)) {
+			if ((cur_time == battery_info->last_time) || (current == battery_info->last_level)) {
 				/* if we can't calculate because nothing changed, use last 
-				 * chargeRate to prevent removing battery.remaining_time.
+				 * rate to prevent removing battery.remaining_time.
 				 */
-				chargeRate = battery_info->last_chargeRate;
+				rate = battery_info->last_rate;
 			} else {
-				chargeRate = ((chargeLevel - battery_info->last_level) * 60 * 60) / (cur_time - battery_info->last_time);
+				rate = ((current - battery_info->last_level) * 60 * 60) / (cur_time - battery_info->last_time);
 				/*
-				 * During discharging chargeRate would be negative, which would
+				 * During discharging rate would be negative, which would
 				 * mess up the the calculation below, so we make sure it's always
 				 * positive.
 				 */ 
-				chargeRate = (chargeRate > 0) ? chargeRate : -chargeRate;
+				rate = (rate > 0) ? rate : -rate;
 	
-				battery_info->last_level = chargeLevel;
+				battery_info->last_level = current;
 				battery_info->last_time = cur_time;
-				battery_info->last_chargeRate = chargeRate;
+				battery_info->last_rate = rate;
 			}
 		} else {
 			battery_info = g_new0(batteryInfo, 1);
 			g_hash_table_insert(saved_battery_info, (char*) id, battery_info);
 
-			battery_info->last_level = chargeLevel;
+			battery_info->last_level = current;
 			battery_info->last_time = cur_time;
-			battery_info->last_chargeRate = 0;
+			battery_info->last_rate = 0;
  			return -1;
 		}
 	} 
 
-	if (chargeRate == 0)
+	HAL_WARNING (("rate is %i", rate));
+
+	if (rate == 0)
 		return -1;
 
-	if (isDischarging) { 
-		remaining_time = ((double) chargeLevel / (double) chargeRate) * 60 * 60;
-	} else if (isCharging) {
+	if (is_discharging) { 
+		remaining_time = ((double) current / (double) rate) * 60 * 60;
+	} else if (is_charging) {
 		/* 
-		 * Some ACPI BIOS's don't update chargeLastFull, 
-		 * so return 0 as we don't know how much more there is left
+		 * Some ACPI BIOS's don't update last_full, 
+		 * so return missing as we don't know how much more there is left
 		 */
-		if (chargeLevel > chargeLastFull ) {
-			HAL_WARNING (("chargeLevel > chargeLastFull, returning -1"));
+		if (current > last_full ) {
+			HAL_WARNING (("current > last_full, returning -1"));
 			return -1;
 		}
-		remaining_time = ((double) (chargeLastFull - chargeLevel) / (double) chargeRate) * 60 * 60;
+		remaining_time = ((double) (last_full - current) / (double) rate) * 60 * 60;
 	}
 	
 	/* This shouldn't happen, but check for completeness */
diff --git a/hald/util_pm.h b/hald/util_pm.h
index 977531e..b17ec55 100644
--- a/hald/util_pm.h
+++ b/hald/util_pm.h
@@ -29,9 +29,9 @@ #define UTIL_PM_H
 
 const char *util_get_battery_technology (const char *type);
 
+/* depreciated */
 int util_compute_time_remaining (const char *id, int chargeRate, int chargeLevel, int chargeLastFull, 
 				 gboolean isDischarging, gboolean isCharging, gboolean guessChargeRate);
-
 int util_compute_percentage_charge (const char *id, int chargeLevel, int chargeLastFull);
 
 #endif /* UTIL__PM_H */
--- /dev/null	2006-10-16 22:06:18.000000000 +0100
+++ hald/util_battery.c	2006-11-06 01:38:29.000000000 +0000
@@ -0,0 +1,323 @@
+/***************************************************************************
+ *
+ * util_battery.c - Battery class
+ *
+ * Copyright (C) 2005-2006 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2005 Danny Kukawka <danny.kukawka@web.de>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+
+#include "logger.h"
+#include "device_info.h"
+#include "util_battery.h"
+
+HalBattery *
+util_battery_get_data (HalDevice *d)
+{
+	HalBattery *bat;
+	bat = g_object_get_data ((gpointer) d, "battery-object");
+	return bat;
+}
+
+void
+util_battery_set_unit_from_string (HalBattery *bat, const char *unit)
+{
+	bat->unit = HAL_BATTERY_TYPE_UNKNOWN;
+
+	/* if the hardware does not set a unit, assume mWh */
+	if (unit == NULL) {
+		bat->unit = HAL_BATTERY_TYPE_MWH;
+	} else {
+		if (strcmp (unit, "mAh") == 0) {
+			bat->unit = HAL_BATTERY_TYPE_MAH;
+		} else if (strcmp (unit, "mWh") == 0) {
+			bat->unit = HAL_BATTERY_TYPE_MWH;
+		}
+	}
+}
+
+void
+util_battery_check_voltage (HalDevice *d, HalBattery *bat)
+{
+	/* Just in case we don't get design voltage information, then
+	 * this will pretend that we have 10V.  This degrades our
+	 * ability to report accurate times on multi-battery systems
+	 * but will always prevent negative charge levels and allow
+	 * accurate reporting on single-battery systems.
+	 */
+	if (bat->design_voltage <= 0 || bat->design_voltage > 300000) {
+		HAL_DEBUG (("Design voltage is invalid or over 300V"));
+		bat->design_voltage = 10000; /* mV */
+	}
+
+	/* If the current voltage is unknown, smaller than 50% of design voltage (fd.o #8593) 
+	 * or greater than design, then use design voltage.
+	 */
+	if (bat->voltage < (bat->design_voltage / 2)  || bat->voltage > bat->design_voltage) {
+		HAL_DEBUG (("Current voltage is unknown, smaller than 50%% or greater than design"));
+		bat->voltage = bat->design_voltage;
+	}
+
+	HAL_DEBUG (("battery voltage\t%i", bat->voltage));
+}
+
+static void
+util_battery_normalise_mwh (HalDevice *d, HalBattery *bat)
+{
+	/* We are converting the unknown units into mWh because of ACPI's nature
+	 * of not having a standard "energy" unit.
+	 *
+	 * full details here: http://bugzilla.gnome.org/show_bug.cgi?id=309944
+	 */
+	if (bat->unit == HAL_BATTERY_TYPE_MAH) {
+		/* convert mAh to mWh by multiplying by voltage. */
+		bat->current = (bat->current * bat->voltage) / 1000;
+		bat->last_full = (bat->last_full * bat->voltage) / 1000;
+		bat->rate = (bat->rate * bat->voltage) / 1000;
+	}
+	HAL_DEBUG (("battery rate\t%i", bat->rate));
+	HAL_DEBUG (("battery last_full\t%i", bat->last_full));
+	HAL_DEBUG (("battery current\t%i", bat->current));
+}
+
+static void
+util_battery_calculate_rate (HalDevice *d, HalBattery *bat)
+{
+	time_t cur_time;
+	gboolean use_fixup;
+
+	/*
+	 * 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.
+	 *
+	 * full details here: http://bugzilla.gnome.org/show_bug.cgi?id=348201
+	 */
+	if (bat->rate == 0xffff || bat->rate == 0xffffff) {
+		bat->rate = -1;
+		goto out;
+	}
+
+	/*
+	 * Some laptops report a rate even when not charging or discharging.
+	 * If not charging and not discharging force rate to be zero.
+         *
+         * http://bugzilla.gnome.org/show_bug.cgi?id=323186
+	 */
+	if (!bat->is_charging && !bat->is_discharging) {
+		bat->rate = 0;
+		goto out;
+	}
+
+	/* should not get negative values */
+	if (bat->rate < 0 || bat->current < 0 || bat->last_full < 0) {
+		HAL_WARNING (("rate, current or last_full < 0, returning -1"));
+		bat->rate = -1;
+		goto out;
+	}
+	/* batteries cannot charge and discharge at the same time */
+	if (bat->is_discharging && bat->is_charging) {
+		HAL_WARNING (("is_discharging & is_charging TRUE, returning 0"));
+		bat->rate = 0;
+		goto out;
+	}
+
+	/* 
+	 * Some laptops don't supply any rate info, but that's no reason for HAL not
+	 * to. We use the current and previous current to estimate the rate.
+	 * The info is stored in a GHashTable because there could be more than one battery.
+	 */
+	use_fixup = hal_device_property_get_bool (d, "battery.remaining_time.calculate_per_time");
+	if (TRUE || bat->rate == 0 || use_fixup) {
+		cur_time = time (NULL);
+
+		/* check this to prevent division by zero */
+		if ((cur_time == bat->last_time) || (bat->current == bat->last_level)) {
+			/* if we can't calculate because nothing changed, use last 
+			 * rate to prevent removing battery.remaining_time.
+			 */
+			bat->rate = bat->last_rate;
+		} else {
+			bat->rate = ((bat->current - bat->last_level) * 60 * 60) / (cur_time - bat->last_time);
+			/*
+			 * During discharging rate would be negative, which would
+			 * mess up the the calculation below, so we make sure it's always
+			 * positive.
+			 */
+			if (bat->rate < 0) {
+				bat->rate = -bat->rate;
+			}
+			bat->last_level = bat->current;
+			bat->last_time = cur_time;
+		}
+	} 
+
+	/* don't even store the key if we can't calculate it */
+	if (bat->rate == 0) {
+		bat->rate = -1;
+		goto out;
+	}
+out:
+	HAL_DEBUG (("battery rate\t%i", bat->rate));
+}
+
+static void
+util_battery_calculate_time_remaining (HalDevice *d, HalBattery *bat)
+{
+	if (bat->rate == 0) {
+		HAL_WARNING (("zero rate, setting -1"));
+		bat->remaining_time = -1;
+		goto out;
+	}
+
+	if (bat->is_discharging) { 
+		bat->remaining_time = ((double) bat->current / (double) bat->rate) * 60 * 60;
+	} else if (bat->is_charging) {
+		bat->remaining_time = ((double) (bat->last_full - bat->current) / (double) bat->rate) * 60 * 60;
+	}
+	
+	/* This shouldn't happen, but check for completeness */
+	if (bat->remaining_time < 0) {
+		HAL_WARNING (("remaining_time %i, setting -1", bat->remaining_time));
+		bat->remaining_time = -1;
+		goto out;
+	}
+
+	/* Battery life cannot be above 60 hours */
+	if (bat->remaining_time > 60 * 60 * 60) {
+		HAL_WARNING (("remaining_time *very* high, returning -1"));
+		bat->remaining_time = -1;
+		goto out;
+	}
+out:
+	HAL_DEBUG (("battery time\t%i", bat->remaining_time));
+}
+
+static void
+util_battery_check_charge (HalDevice *d, HalBattery *bat)
+{
+	/*
+	 * Some laptops report current charge much larger than
+	 * full charge when at 100%.  Clamp back down to 100%.
+	 */
+	if (bat->current > bat->last_full) {
+	  	bat->current = bat->last_full;
+	}
+}
+
+/* writes the HalBattery struct to the tree as battery.charge_level.* */
+static void
+util_battery_commit (HalDevice *d, HalBattery *bat)
+{
+	/*
+	 * Only set keys if no error (signified with negative return value)
+	 * Scrict checking is needed to ensure that the values presented by HAL
+	 * are 100% acurate.
+	 */
+	if (bat->current > 0) {
+		hal_device_property_set_int (d, "battery.charge_level.current", bat->current);
+	} else {
+		hal_device_property_remove (d, "battery.charge_level.current");
+	}
+	if (bat->last_full > 0) {
+		hal_device_property_set_int (d, "battery.charge_level.last_full", bat->last_full);
+	} else {
+		hal_device_property_remove (d, "battery.charge_level.last_full");
+	}
+	if (bat->rate > 0) {
+		hal_device_property_set_int (d, "battery.charge_level.rate", bat->rate);
+	} else {
+		hal_device_property_remove (d, "battery.charge_level.rate");
+	}
+	if (bat->percentage > 0) {
+		hal_device_property_set_int (d, "battery.charge_level.percentage", bat->percentage);
+	} else {
+		hal_device_property_remove (d, "battery.charge_level.percentage");
+	}
+	if (bat->percentage > 0) {
+		hal_device_property_set_int (d, "battery.remaining_time", bat->remaining_time);
+	} else {
+		hal_device_property_remove (d, "battery.remaining_time");
+	}
+}
+
+static void 
+util_battery_compute_percentage_charge (HalDevice *d, HalBattery *bat)
+{
+	int percentage;
+	/* make sure we have chargelevel */
+	if (bat->current <= 0) {
+		HAL_WARNING (("current %i, set to -1!", bat->current));
+		percentage = -1;
+		goto out;
+	}
+	/* make sure not division by zero */
+	if (bat->last_full > 0)
+		percentage = ((double) bat->current / (double) bat->last_full) * 100;
+	else {
+		HAL_WARNING (("last_full %i, percentage set to -1!", bat->last_full));
+		percentage = -1;
+		goto out;
+	}
+	/* Some bios's will report this higher than 100, limit it here */
+	if (percentage > 100) {
+		HAL_WARNING (("Percentage %i, set to 100", percentage));
+		percentage = 100;
+		goto out;
+	}
+	/* Something really isn't right if we get a negative... */
+	if (percentage < 0) {
+		HAL_WARNING (("Percentage %i, set to -1!", percentage));
+		percentage = -1;
+		goto out;
+	}
+out:
+	bat->percentage = percentage;
+}
+
+void
+util_battery_update_values (HalDevice *d)
+{
+	HalBattery *bat;
+
+	/* get battery object */
+	bat = util_battery_get_data (d);
+	if (bat == NULL) {
+		HAL_WARNING (("Battery object not found"));
+		return;
+	}
+
+	util_battery_check_voltage (d, bat);
+	util_battery_normalise_mwh (d, bat);
+	util_battery_check_charge (d, bat);
+	util_battery_compute_percentage_charge (d, bat);
+	util_battery_calculate_rate (d, bat);
+	util_battery_calculate_time_remaining (d, bat);
+	util_battery_commit (d, bat);
+}
--- /dev/null	2006-10-16 22:06:18.000000000 +0100
+++ hald/util_battery.h	2006-11-06 01:37:09.000000000 +0000
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *
+ * util_battery.c - Battery class
+ *
+ * Copyright (C) 2006 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifndef UTIL_BATTERY_H
+#define UTIL_BATTERY_H
+
+#include "device.h"
+#include "device_store.h"
+
+typedef enum {
+	HAL_BATTERY_TYPE_MWH,
+	HAL_BATTERY_TYPE_MAH,
+	HAL_BATTERY_TYPE_UNKNOWN
+} HalBatteryType;
+
+typedef struct {
+	HalBatteryType 	unit;
+	const char	*udi;
+	const char	*path;
+	gboolean	is_charging;
+	gboolean	is_discharging;
+	int		current;
+	int		last_full;
+	int		rate;
+	int		design_voltage;
+	int		voltage;
+	int		remaining_time;
+	int		percentage;
+	/* needed for rate calculations */
+	int		last_level;
+	int		last_rate;
+	time_t		last_time;
+} HalBattery;
+
+HalBattery *util_battery_get_data (HalDevice *d);
+void util_battery_update_values (HalDevice *d);
+void util_battery_check_voltage (HalDevice *d, HalBattery *bat);
+void util_battery_set_unit_from_string (HalBattery *bat, const char *unit);
+
+#endif /* UTIL_BATTERY_H */