diff options
author | Benjamin Berg <bberg@redhat.com> | 2022-06-15 15:50:36 +0200 |
---|---|---|
committer | Benjamin Berg <bberg@redhat.com> | 2022-06-21 11:16:01 +0200 |
commit | 9097b57b3bb1896b3911671a9a1c9efec29c96e1 (patch) | |
tree | e89dbc01a000bda1c06ff6b8830958a654e85bbb | |
parent | 6fedd0f20a64b9996226d0a2d26682a95aa7adb2 (diff) | |
download | upower-9097b57b3bb1896b3911671a9a1c9efec29c96e1.tar.gz |
battery: Guess charging/discharging state based on energy rate
This should be quite robust, in particular as we should be getting
notifications about AC plug/unplug.
The value for the battery will lag a few seconds. However, the
DisplayDevice will do some guessing taking the AC state into account,
and as such the user should get at least some immediate feedback.
Closes: #196
-rw-r--r-- | src/up-device-battery.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/src/up-device-battery.c b/src/up-device-battery.c index 2300568..544dedd 100644 --- a/src/up-device-battery.c +++ b/src/up-device-battery.c @@ -90,7 +90,7 @@ up_device_battery_charge_to_energy (UpDeviceBattery *self, gdouble charge) } static void -up_device_battery_estimate (UpDeviceBattery *self) +up_device_battery_estimate (UpDeviceBattery *self, UpDeviceState *effective_state) { UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self); UpBatteryValues *ref = NULL; @@ -106,7 +106,11 @@ up_device_battery_estimate (UpDeviceBattery *self) priv->have_good_estimates = FALSE; cur = &priv->hw_data[priv->hw_data_last]; - if (cur->state != UP_DEVICE_STATE_CHARGING && cur->state != UP_DEVICE_STATE_DISCHARGING) { + *effective_state = cur->state; + + if (*effective_state != UP_DEVICE_STATE_CHARGING && + *effective_state != UP_DEVICE_STATE_DISCHARGING && + *effective_state != UP_DEVICE_STATE_UNKNOWN) { priv->have_good_estimates = TRUE; goto out; } @@ -115,7 +119,7 @@ up_device_battery_estimate (UpDeviceBattery *self) int pos = (priv->hw_data_last - i + G_N_ELEMENTS (priv->hw_data)) % G_N_ELEMENTS (priv->hw_data); gint64 td; - /* Stop searching if the state changed. */ + /* Stop searching if the hardware state changed. */ if (priv->hw_data[pos].state != cur->state) break; @@ -147,14 +151,30 @@ up_device_battery_estimate (UpDeviceBattery *self) /* energy is in Wh, rate in W */ energy_rate = (cur->energy.cur - ref->energy.cur) / (ref_td / ((gdouble) 3600 * G_USEC_PER_SEC)); + /* Try to guess charge/discharge state based on rate. + * Note that the history is discarded when the AC is plugged, as such + * we should only err on the side of showing CHARGING for too long. + */ + if (*effective_state == UP_DEVICE_STATE_UNKNOWN) { + /* Consider a rate of 0.5W as "no change", otherwise set CHARGING/DISCHARGING */ + if (abs(energy_rate) < 0.5) { + priv->have_good_estimates = TRUE; + goto out; + } else if (energy_rate < 0.0) { + *effective_state = UP_DEVICE_STATE_DISCHARGING; + } else { + *effective_state = UP_DEVICE_STATE_CHARGING; + } + } + /* The rate is defined to be positive during both charge and discharge. */ - if (cur->state == UP_DEVICE_STATE_DISCHARGING) + if (*effective_state == UP_DEVICE_STATE_DISCHARGING) energy_rate *= -1.0; /* This hopefully gives us sane values, but lets print a message if not. */ if (energy_rate < 0.1 || energy_rate > 300) { g_message ("The estimated %scharge rate is %fW, which is not realistic", - cur->state == UP_DEVICE_STATE_DISCHARGING ? "dis" : "", + *effective_state == UP_DEVICE_STATE_DISCHARGING ? "dis" : "", energy_rate); energy_rate = 0; goto out; @@ -162,7 +182,7 @@ up_device_battery_estimate (UpDeviceBattery *self) /* Here we could factor in collected data about charge rates */ /* FIXME: Use charge-stop-threshold here */ - if (cur->state == UP_DEVICE_STATE_CHARGING) + if (*effective_state == UP_DEVICE_STATE_CHARGING) time_to_full = 3600 * (priv->energy_full - cur->energy.cur) / energy_rate; else time_to_empty = 3600 * cur->energy.cur / energy_rate; @@ -235,8 +255,8 @@ up_device_battery_report (UpDeviceBattery *self, return; } - /* Discard all old measurements (from before suspend). */ - if (reason == UP_REFRESH_RESUME) + /* 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); @@ -321,7 +341,7 @@ up_device_battery_report (UpDeviceBattery *self, priv->hw_data[priv->hw_data_last] = *values; /* Do estimations */ - up_device_battery_estimate (self); + up_device_battery_estimate (self, &values->state); /* Set the main properties (setting "update-time" last) */ g_object_set (self, |