Solid

winbattery.cpp
1/*
2 SPDX-FileCopyrightText: 2013 Patrick von Reth <vonreth@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#include "winbattery.h"
7#include "windevicemanager_p.h"
8
9#include <batclass.h>
10#include <devguid.h>
11#include <devpropdef.h>
12#include <setupapi.h>
13
14using namespace Solid::Backends::Win;
15
17
18WinBattery::WinBattery(WinDevice *device)
19 : WinInterface(device)
20 , m_state(Solid::Battery::NoCharge)
21{
22 powerChanged();
23 connect(SolidWinEventFilter::instance(), SIGNAL(powerChanged()), this, SLOT(powerChanged()));
24}
25
26Solid::Battery::BatteryType WinBattery::type() const
27{
28 return m_type;
29}
30
31int WinBattery::chargePercent() const
32{
33 return m_charge;
34}
35
36int WinBattery::capacity() const
37{
38 return m_capacity;
39}
40
41bool WinBattery::isRechargeable() const
42{
43 return m_rechargeable;
44}
45
46bool WinBattery::isPowerSupply() const
47{
48 return m_isPowerSupply;
49}
50
51Solid::Battery::ChargeState WinBattery::chargeState() const
52{
53 return m_state;
54}
55
56QSet<QString> WinBattery::getUdis()
57{
58 QSet<QString> udis;
59 HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
60
61 if (INVALID_HANDLE_VALUE != hdev) {
62 // Limit search to 100 batteries max
63 for (int idev = 0; idev < 100; idev++) {
64 SP_DEVICE_INTERFACE_DATA did;
65 ZeroMemory(&did, sizeof(did));
66 did.cbSize = sizeof(did);
67
68 if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVCLASS_BATTERY, idev, &did)) {
69 DWORD cbRequired = 0;
70
71 SetupDiGetDeviceInterfaceDetailW(hdev, &did, 0, 0, &cbRequired, 0);
72 if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
73 char *buffer = new char[cbRequired];
74 SP_DEVICE_INTERFACE_DETAIL_DATA *pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA *)buffer;
75 ZeroMemory(pdidd, cbRequired);
76 pdidd->cbSize = sizeof(*pdidd);
77 if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0)) {
78 QString path = QString::fromWCharArray(pdidd->DevicePath);
79 ulong tag = WinDeviceManager::getDeviceInfo<ulong>(path, IOCTL_BATTERY_QUERY_TAG);
80 QString udi = QLatin1String("/org/kde/solid/win/power.battery/battery#") + QString::number(tag);
81 udis << udi;
82 m_udiToGDI[udi] = Battery(path, tag);
83 }
84 delete[] buffer;
85 }
86 }
87 }
88
89 SetupDiDestroyDeviceInfoList(hdev);
90 }
91 return udis;
92}
93
94const WinBattery::Battery WinBattery::batteryInfoFromUdi(const QString &udi)
95{
96 return m_udiToGDI[udi];
97}
98
99void WinBattery::powerChanged()
100{
101 const int old_charge = m_charge;
102 const int old_capacity = m_capacity;
103 const Solid::Battery::ChargeState old_state = m_state;
104 const bool old_isPowerSupply = m_isPowerSupply;
105 const double old_energy = m_energy;
106 const double old_energyFull = m_energyFull;
107 const double old_energyFullDesign = m_energyFullDesign;
108 const double old_energyRate = m_energyRate;
109 const double old_voltage = m_voltage;
110
111 BATTERY_WAIT_STATUS batteryStatusQuery;
112 ZeroMemory(&batteryStatusQuery, sizeof(batteryStatusQuery));
113 Battery b = m_udiToGDI[m_device->udi()];
114 batteryStatusQuery.BatteryTag = b.second;
115 BATTERY_STATUS status = WinDeviceManager::getDeviceInfo<BATTERY_STATUS, BATTERY_WAIT_STATUS>(b.first, IOCTL_BATTERY_QUERY_STATUS, &batteryStatusQuery);
116
117 BATTERY_QUERY_INFORMATION batteryInformationQuery;
118 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
119 batteryInformationQuery.BatteryTag = b.second;
120 batteryInformationQuery.InformationLevel = BatteryInformation;
121 BATTERY_INFORMATION info =
122 WinDeviceManager::getDeviceInfo<BATTERY_INFORMATION, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery);
123
124 initSerial(b);
125 updateBatteryTemp(b);
126 updateTimeToEmpty(b);
127
128 m_isPowerSupply = !(status.PowerState & BATTERY_POWER_ON_LINE);
129
130 QString tech = QString::fromUtf8((const char *)info.Chemistry, 4);
131
132 if (tech == "LION" || tech == "LI-I") {
133 m_technology = Solid::Battery::LithiumIon;
134 } else if (tech == "PBAC") {
135 m_technology = Solid::Battery::LeadAcid;
136 } else if (tech == "NICD") {
137 m_technology = Solid::Battery::NickelCadmium;
138 } else if (tech == "NIMH") {
139 m_technology = Solid::Battery::NickelMetalHydride;
140 } else {
141 m_technology = Solid::Battery::UnknownTechnology;
142 }
143
144 m_energy = status.Capacity / 1000.0; // provided in mWh
145 m_energyFull = info.FullChargedCapacity / 1000.0; // provided in mWh
146 m_energyFullDesign = info.DesignedCapacity / 1000.0; // provided in mWh
147 m_energyRate = status.Rate / 1000.0; // provided in mW
148 m_voltage = status.Voltage / 1000.0; // provided in mV
149
150 if (info.FullChargedCapacity != 0) {
151 m_charge = (float)status.Capacity / info.FullChargedCapacity * 100.0;
152 }
153
154 if (info.DesignedCapacity != 0) {
155 m_capacity = (float)info.FullChargedCapacity / info.DesignedCapacity * 100.0;
156 }
157
158 if (status.PowerState == 0) {
159 m_state = Solid::Battery::NoCharge;
160 } else if (status.PowerState & BATTERY_CHARGING) {
161 m_state = Solid::Battery::Charging;
162 } else if (status.PowerState & BATTERY_DISCHARGING) {
163 m_state = Solid::Battery::Discharging;
164 }
165 // else if(info.PowerState & 0x00000008)//critical
166 // {
167
168 // }
169
170 if (info.Capabilities & BATTERY_SYSTEM_BATTERY) {
171 m_type = Solid::Battery::PrimaryBattery;
172 } else {
173 m_type = Solid::Battery::UnknownBattery;
174 }
175
176 m_rechargeable = info.Technology == 1;
177
178 if (m_charge != old_charge) {
179 Q_EMIT chargePercentChanged(m_charge, m_device->udi());
180 }
181
182 if (m_capacity != old_capacity) {
183 Q_EMIT capacityChanged(m_capacity, m_device->udi());
184 }
185
186 if (old_state != m_state) {
187 Q_EMIT chargeStateChanged(m_state, m_device->udi());
188 }
189
190 if (old_isPowerSupply != m_isPowerSupply) {
191 Q_EMIT powerSupplyStateChanged(m_isPowerSupply, m_device->udi());
192 }
193
194 if (old_energy != m_energy) {
195 Q_EMIT energyChanged(m_energy, m_device->udi());
196 }
197
198 if (old_energyFull != m_energyFull) {
199 Q_EMIT energyFullChanged(m_energyFull, m_device->udi());
200 }
201
202 if (old_energyFullDesign != m_energyFullDesign) {
203 Q_EMIT energyFullDesignChanged(m_energyFullDesign, m_device->udi());
204 }
205
206 if (old_energyRate != m_energyRate) {
207 Q_EMIT energyRateChanged(m_energyRate, m_device->udi());
208 }
209
210 if (old_voltage != m_voltage) {
211 Q_EMIT voltageChanged(m_voltage, m_device->udi());
212 }
213}
214
215void WinBattery::initSerial(const Battery &b)
216{
217 wchar_t buffer[1024];
218 BATTERY_QUERY_INFORMATION batteryInformationQuery;
219 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
220 batteryInformationQuery.BatteryTag = b.second;
221 batteryInformationQuery.InformationLevel = BatterySerialNumber;
222 WinDeviceManager::getDeviceInfo<wchar_t, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, buffer, 1024, &batteryInformationQuery);
223
224 m_serial = QString::fromWCharArray(buffer);
225}
226
227void WinBattery::updateTimeToEmpty(const WinBattery::Battery &b)
228{
229 BATTERY_QUERY_INFORMATION batteryInformationQuery;
230 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
231 batteryInformationQuery.BatteryTag = b.second;
232 batteryInformationQuery.InformationLevel = BatteryEstimatedTime;
233 ulong time = WinDeviceManager::getDeviceInfo<ulong, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery);
234
235 if (time == BATTERY_UNKNOWN_TIME) {
236 time = 0;
237 }
238
239 if (time != m_timeUntilEmpty) {
240 m_timeUntilEmpty = time;
241 Q_EMIT timeToEmptyChanged(time, m_device->udi());
242 }
243}
244
245void WinBattery::updateBatteryTemp(const WinBattery::Battery &b)
246{
247 BATTERY_QUERY_INFORMATION batteryInformationQuery;
248 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
249 batteryInformationQuery.BatteryTag = b.second;
250 batteryInformationQuery.InformationLevel = BatteryTemperature;
251 ulong batteryTemp = WinDeviceManager::getDeviceInfo<ulong, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery);
252
253 if (batteryTemp != m_temperature) {
254 m_temperature = batteryTemp;
255 Q_EMIT temperatureChanged(batteryTemp, m_device->udi());
256 }
257}
258
259Solid::Battery::Technology WinBattery::technology() const
260{
261 return m_technology;
262}
263
264double WinBattery::energy() const
265{
266 return m_energy;
267}
268
269double WinBattery::energyFull() const
270{
271 return m_energyFull;
272}
273
274double WinBattery::energyFullDesign() const
275{
276 return m_energyFullDesign;
277}
278
279double WinBattery::energyRate() const
280{
281 return m_energyRate;
282}
283
284double WinBattery::voltage() const
285{
286 return m_voltage;
287}
288
289bool WinBattery::isPresent() const
290{
291 return true;
292}
293
294qlonglong WinBattery::timeToEmpty() const
295{
296 return m_timeUntilEmpty;
297}
298
299qlonglong WinBattery::timeToFull() const
300{
301 return 0;
302}
303
304double WinBattery::temperature() const
305{
306 return m_temperature;
307}
308
309qlonglong WinBattery::remainingTime() const
310{
311 return m_timeUntilEmpty; // FIXME
312}
313
314QString WinBattery::serial() const
315{
316 return m_serial;
317}
318
319#include "moc_winbattery.cpp"
This device interface is available on batteries.
BatteryType
This enum type defines the type of the device holding the battery.
Technology
Technology used in the battery.
ChargeState
This enum type defines charge state of a battery.
Q_SCRIPTABLE CaptureState status()
QString path(const QString &relativePath)
The single responsibility of this class is to create arguments valid for logind Inhibit call.
Definition fakebattery.h:16
Q_EMITQ_EMIT
QString fromUtf8(QByteArrayView str)
QString fromWCharArray(const wchar_t *string, qsizetype size)
QString number(double n, char format, int precision)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:12 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.