summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Berg <bberg@redhat.com>2022-07-15 18:58:17 +0200
committerBenjamin Berg <bberg@redhat.com>2022-07-21 11:06:49 +0200
commitc2d77ae251b477d47093ff220697d37b0b14db7f (patch)
tree5cefcb6aac19c24cdd1dfa088a0d8444cd03695d
parent1ab1b70d4adbc3962852a76d0fe859d64261d366 (diff)
downloadupower-c2d77ae251b477d47093ff220697d37b0b14db7f.tar.gz
battery: User power/current reading from battery
This switches to always use the power/current reading if we had a sensible reading at some point in the past. In contrast to the older UPower code, will will however ignore the reading for 10 seconds after a discontinuity (power plug/unplug or resume) unless we read an explicit zero value after the event happened. We do this under the assumption that the readings may be wildly off, and it is better to not show an estimate rather than one that is wildly incorrect. Note that this commit also normalises negative power readings while discharging to be positive. Closes: #199
-rw-r--r--src/up-constants.h2
-rw-r--r--src/up-device-battery.c43
2 files changed, 38 insertions, 7 deletions
diff --git a/src/up-constants.h b/src/up-constants.h
index 660e7fd..fdd2e0e 100644
--- a/src/up-constants.h
+++ b/src/up-constants.h
@@ -32,6 +32,8 @@ G_BEGIN_DECLS
#define UP_DAEMON_SHORT_TIMEOUT 30 /* seconds */
#define UP_DAEMON_LONG_TIMEOUT 120 /* seconds */
+#define UP_DAEMON_DISTRUST_RATE_TIMEOUT 10 /* second */
+
#define UP_FULLY_CHARGED_THRESHOLD 90 /* % */
#define UP_DAEMON_EPSILON 0.01 /* I can't believe it's not zero */
diff --git a/src/up-device-battery.c b/src/up-device-battery.c
index c88a276..5874901 100644
--- a/src/up-device-battery.c
+++ b/src/up-device-battery.c
@@ -46,6 +46,9 @@ typedef struct {
gdouble energy_design;
gint charge_cycles;
+ gboolean trust_power_measurement;
+ gint64 last_power_discontinuity;
+
/* dynamic values */
gint64 fast_repoll_until;
gboolean repoll_needed;
@@ -160,7 +163,7 @@ up_device_battery_estimate_power (UpDeviceBattery *self, UpBatteryValues *cur)
cur->state = UP_DEVICE_STATE_CHARGING;
}
- /* The rate is defined to be positive during both charge and discharge. */
+ /* QUIRK: No good reason, but define rate to be positive. */
if (cur->state == UP_DEVICE_STATE_DISCHARGING)
energy_rate *= -1.0;
@@ -236,14 +239,20 @@ up_device_battery_report (UpDeviceBattery *self,
return;
}
- /* Discard all old measurements that can't be used for estimations. */
- if (reason == UP_REFRESH_RESUME || reason == UP_REFRESH_LINE_POWER)
- priv->hw_data_len = 0;
-
g_assert (priv->units != UP_BATTERY_UNIT_UNDEFINED);
values->ts_us = g_get_monotonic_time ();
+ /* Discard all old measurements that can't be used for estimations.
+ *
+ * XXX: Should a state change also trigger an update of the timestamp
+ * that is used to discard power/current measurements?
+ */
+ if (reason == UP_REFRESH_RESUME || reason == UP_REFRESH_LINE_POWER) {
+ priv->hw_data_len = 0;
+ priv->last_power_discontinuity = values->ts_us;
+ }
+
/* QUIRK:
*
* There is an old bug where some Lenovo machine switched from reporting
@@ -312,8 +321,27 @@ up_device_battery_report (UpDeviceBattery *self,
* about the AC state and we only have "one" battery.
*/
- /* Do power estimations based on energy/charge data */
- up_device_battery_estimate_power (self, values);
+ /* QUIRK: No good reason, but define rate to be positive.
+ *
+ * It would be sane/reasonable to define it to be negative when
+ * discharging. Only odd thing is that most common hardware appears
+ * to always report positive values, which appeared in DBus unmodified.
+ */
+ if (values->state == UP_DEVICE_STATE_DISCHARGING && values->energy.rate < 0)
+ values->energy.rate = -values->energy.rate;
+
+ /* NOTE: We got a (likely sane) reading.
+ * Assume power/current readings are accurate from now on. */
+ if (values->energy.rate > 0.01)
+ priv->trust_power_measurement = TRUE;
+
+ if (priv->trust_power_measurement) {
+ /* QUIRK: Do not trust readings after a discontinuity happened */
+ if (priv->last_power_discontinuity + UP_DAEMON_DISTRUST_RATE_TIMEOUT * G_USEC_PER_SEC > values->ts_us)
+ values->energy.rate = 0.0;
+ } else {
+ up_device_battery_estimate_power (self, values);
+ }
/* Push into our ring buffer */
@@ -467,6 +495,7 @@ up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info)
/* NOTE: Assume a normal refresh will follow immediately (do not update timestamp). */
} else {
priv->present = FALSE;
+ priv->trust_power_measurement = FALSE;
priv->hw_data_len = 0;
priv->units = UP_BATTERY_UNIT_UNDEFINED;