Current implementation of system.fill_battery_state only reads "charge_*" and "current_*" attributes. Some batteries expose different attributes, namely "power_*" and "energy_*". Added the required logic to support both types.
Further, when rewriting the function I also added support for systems with multiple batteries. Windows documentation was not clear but from what I gathered struct SYSTEM_BATTERY_STATE sets Charging and Discharging if ANY battery is charging/discharging. So, to check if the overall system is charging/discharging only Rate can be used.
Also cleaned the code related to "AC". There was a "fixme" there which I didn't fully undertand as SYSTEM_BATTERY_STATE.AcOnLine == True if any AC is present, so the proper logic was already implemented
From: Tomas Mendes rtdiasmendes@gmail.com
--- dlls/ntdll/tests/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index ee48a330400..21c7ec1f18d 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -1654,7 +1654,7 @@ static void test_query_battery(void)
if (!bs.BatteryPresent) time_left = 0; - else if (!bs.Charging && (LONG)bs.Rate < 0) + else if ((LONG)bs.Rate < 0) time_left = 3600 * bs.RemainingCapacity / -(LONG)bs.Rate; else time_left = ~0u;
From: Tomas Mendes rtdiasmendes@gmail.com
--- dlls/ntdll/unix/system.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 950a9655dc7..775e2806403 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -223,6 +223,28 @@ struct smbios_wine_core_id_regs_arm64 } regs[]; };
+enum battery_status { + BATTERY_UNKNOWN, + BATTERY_CHARGING, + BATTERY_DISCHARGING, + BATTERY_NOT_CHARGING, + BATTERY_FULL +}; + +struct linux_battery +{ + enum battery_status status; + unsigned int present; + int power_unit; + int full_charge_capacity; + int capacity_now; + int rate_now; + int voltage_now; + int alarm; + int capacity_alert_min; + int capacity_alert_max; +}; + #pragma pack(pop)
enum smbios_type
From: Tomas Mendes rtdiasmendes@gmail.com
--- dlls/ntdll/unix/system.c | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 775e2806403..551ef10980e 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -4018,6 +4018,48 @@ static const char * get_sys_str(const char *dirname, const char *basename, char return ret; }
+static enum battery_status parse_battery_status(const char *s) +{ + if (strcmp(s, "Charging\n") == 0) return BATTERY_CHARGING; + if (strcmp(s, "Discharging\n") == 0) return BATTERY_DISCHARGING; + if (strcmp(s, "Not charging\n") == 0) return BATTERY_NOT_CHARGING; + if (strcmp(s, "Full\n") == 0) return BATTERY_FULL; + return BATTERY_UNKNOWN; +} + +static void get_sys_bat(const char *path, struct linux_battery *bat) +{ + char s[16]; + + bat->present = get_sys_int(path, "present"); + if (bat->present) return; + + get_sys_str(path, "status", s); + bat->status = parse_battery_status(s); + + bat->full_charge_capacity = get_sys_int(path, "energy_full"); + bat->capacity_now = get_sys_int(path, "energy_now"); + bat->rate_now = get_sys_int(path, "power_now"); + bat->power_unit = 1; + + if (!bat->full_charge_capacity || !bat->capacity_now) + { + bat->full_charge_capacity = get_sys_int(path, "charge_full"); + bat->capacity_now = get_sys_int(path, "charge_now"); + bat->voltage_now = get_sys_int(path, "voltage_now"); + bat->rate_now = get_sys_int(path, "current_now"); + bat->power_unit = 2; + if (!bat->full_charge_capacity || !bat->capacity_now || !bat->voltage_now) + bat->power_unit = 0; + } + + bat->alarm = get_sys_int(path, "alarm"); + if(bat->alarm) return; + + bat->capacity_alert_min = get_sys_int(path, "capacity_alert_min"); + bat->capacity_alert_max = get_sys_int(path, "capacity_alert_max"); +} + static int get_sys_int(const char *dirname, const char *basename) { char s[16];
From: Tomas Mendes rtdiasmendes@gmail.com
--- dlls/ntdll/unix/system.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 1a0090a83b4..a7acd12a9b4 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -4018,6 +4018,12 @@ static const char * get_sys_str(const char *dirname, const char *basename, char return ret; }
+static int get_sys_int(const char *dirname, const char *basename) +{ + char s[16]; + return get_sys_str(dirname, basename, s) ? atoi(s) : 0; +} + static enum battery_status parse_battery_status(const char *s) { if (strcmp(s, "Charging\n") == 0) return BATTERY_CHARGING; @@ -4060,12 +4066,6 @@ static void get_sys_bat(const char *path, struct linux_battery *bat) bat->capacity_alert_max = get_sys_int(path, "capacity_alert_max"); }
-static int get_sys_int(const char *dirname, const char *basename) -{ - char s[16]; - return get_sys_str(dirname, basename, s) ? atoi(s) : 0; -} - static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs ) { DIR *d = opendir("/sys/class/power_supply");
From: Tomas Mendes rtdiasmendes@gmail.com
--- dlls/kernel32/powermgnt.c | 4 +- dlls/ntdll/unix/system.c | 90 +++++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 30 deletions(-)
diff --git a/dlls/kernel32/powermgnt.c b/dlls/kernel32/powermgnt.c index c4bd97553fe..23c55b1cd83 100644 --- a/dlls/kernel32/powermgnt.c +++ b/dlls/kernel32/powermgnt.c @@ -65,11 +65,11 @@ BOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS ps) { ps->BatteryLifePercent = bs.MaxCapacity ? 100 * bs.RemainingCapacity / bs.MaxCapacity : 100; ps->BatteryLifeTime = bs.EstimatedTime; - if (!bs.Charging && (LONG)bs.Rate < 0) + if ((LONG)bs.Rate < 0) ps->BatteryFullLifeTime = 3600 * bs.MaxCapacity / -(LONG)bs.Rate;
ps->BatteryFlag = 0; - if (bs.Charging) + if (bs.Rate > 0) ps->BatteryFlag |= BATTERY_FLAG_CHARGING; if (ps->BatteryLifePercent > 66) ps->BatteryFlag |= BATTERY_FLAG_HIGH; diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 551ef10980e..1a0090a83b4 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -4071,12 +4071,13 @@ static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs ) DIR *d = opendir("/sys/class/power_supply"); struct dirent *de; char s[16], path[64]; - BOOL found_ac = FALSE; - LONG64 voltage; /* microvolts */ + struct linux_battery bat;
- bs->AcOnLine = TRUE; if (!d) return STATUS_SUCCESS;
+ bs->BatteryPresent = FALSE; + bs->AcOnLine = FALSE; + while ((de = readdir(d))) { if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue; @@ -4084,44 +4085,77 @@ static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs ) if (get_sys_str(path, "scope", s) && strcmp(s, "Device\n") == 0) continue; if (!get_sys_str(path, "type", s)) continue;
- if (strcmp(s, "Mains\n") == 0) + if (!strcmp(s, "Mains\n") && + !bs->AcOnLine && + get_sys_int(path, "online")) + { + bs->AcOnLine = TRUE; + } + else if (!strcmp(s, "Battery\n")) { - if (!get_sys_str(path, "online", s)) continue; - if (found_ac) + get_sys_bat(path, &bat); + + if (!bat.present) continue; + + if (!bs->BatteryPresent) { - FIXME("Multiple mains found, only reporting on the first\n"); + bs->BatteryPresent = TRUE; + bs->Charging = FALSE; + bs->Discharging = FALSE; + bs->MaxCapacity = 0u; + bs->RemainingCapacity = 0u; + bs->Rate = 0u; + bs->EstimatedTime = ~0u; + bs->DefaultAlert1 = 0u; + bs->DefaultAlert2 = 0u; } - else + + if (bat.status == BATTERY_CHARGING && !bs->Charging) bs->Charging = TRUE; + if (bat.status == BATTERY_DISCHARGING && !bs->Discharging) bs->Discharging = TRUE; + + switch (bat.power_unit) + { + case 0: + continue; + case 1: + bs->MaxCapacity += (ULONG)(bat.full_charge_capacity / 1e3); + bs->RemainingCapacity += (ULONG)(bat.capacity_now / 1e3); + if (bat.status == BATTERY_CHARGING) bs->Rate += (ULONG)(bat.rate_now / 1e3); + if (bat.status == BATTERY_DISCHARGING) bs->Rate -= (ULONG)(bat.rate_now / 1e3); + break; + case 2: + bs->MaxCapacity += (ULONG)(bat.full_charge_capacity * bat.voltage_now / 1e9); + bs->RemainingCapacity += (ULONG)(bat.capacity_now * bat.voltage_now / 1e9); + if (bat.status == BATTERY_UNKNOWN || !bat.rate_now) continue; + if (bat.status == BATTERY_DISCHARGING && bat.rate_now > 0) + bs->Rate -= (ULONG)(bat.rate_now * bat.voltage_now / 1e9); + else + bs->Rate += (ULONG)(bat.rate_now * bat.voltage_now / 1e9); + break; + } + + if(bat.alarm) { - bs->AcOnLine = atoi(s); - found_ac = TRUE; + bs->DefaultAlert1 = bs->MaxCapacity / 20; + bs->DefaultAlert2 = (ULONG)(bat.alarm); } - } - else if (strcmp(s, "Battery\n") == 0) - { - if (!get_sys_str(path, "status", s)) continue; - if (bs->BatteryPresent) + else if(bat.capacity_alert_min && bat.capacity_alert_max) { - FIXME("Multiple batteries found, only reporting on the first\n"); + bs->DefaultAlert1 = bs->MaxCapacity * bat.capacity_alert_min / 100; + bs->DefaultAlert2 = bs->MaxCapacity * bat.capacity_alert_max / 100; } else { - bs->Charging = (strcmp(s, "Charging\n") == 0); - bs->Discharging = (strcmp(s, "Discharging\n") == 0); - bs->BatteryPresent = TRUE; - voltage = get_sys_int(path, "voltage_now"); - bs->MaxCapacity = get_sys_int(path, "charge_full") * voltage / 1e9; - bs->RemainingCapacity = get_sys_int(path, "charge_now") * voltage / 1e9; - bs->Rate = -get_sys_int(path, "current_now") * voltage / 1e9; - if (!bs->Charging && (LONG)bs->Rate < 0) - bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate; - else - bs->EstimatedTime = ~0u; + bs->DefaultAlert1 = bs->MaxCapacity / 20; + bs->DefaultAlert2 = bs->MaxCapacity / 3; } } } - closedir(d); + + if (bs->BatteryPresent && (LONG)bs->Rate < 0) + bs->EstimatedTime = 3600 * bs->RemainingCapacity / -bs->Rate; + return STATUS_SUCCESS; }
This merge request was closed by Tomas-Mendes-ai.