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
41int WinBattery::cycleCount() const
42{
43 return m_cycleCount;
44}
45
46bool WinBattery::isRechargeable() const
47{
48 return m_rechargeable;
49}
50
51bool WinBattery::isPowerSupply() const
52{
53 return m_isPowerSupply;
54}
55
56Solid::Battery::ChargeState WinBattery::chargeState() const
57{
58 return m_state;
59}
60
61QSet<QString> WinBattery::getUdis()
62{
63 QSet<QString> udis;
64 HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
65
66 if (INVALID_HANDLE_VALUE != hdev) {
67 // Limit search to 100 batteries max
68 for (int idev = 0; idev < 100; idev++) {
69 SP_DEVICE_INTERFACE_DATA did;
70 ZeroMemory(&did, sizeof(did));
71 did.cbSize = sizeof(did);
72
73 if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVCLASS_BATTERY, idev, &did)) {
74 DWORD cbRequired = 0;
75
76 SetupDiGetDeviceInterfaceDetailW(hdev, &did, 0, 0, &cbRequired, 0);
77 if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
78 char *buffer = new char[cbRequired];
79 SP_DEVICE_INTERFACE_DETAIL_DATA *pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA *)buffer;
80 ZeroMemory(pdidd, cbRequired);
81 pdidd->cbSize = sizeof(*pdidd);
82 if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0)) {
83 QString path = QString::fromWCharArray(pdidd->DevicePath);
84 ulong tag = WinDeviceManager::getDeviceInfo<ulong>(path, IOCTL_BATTERY_QUERY_TAG);
85 QString udi = QLatin1String("/org/kde/solid/win/power.battery/battery#") + QString::number(tag);
86 udis << udi;
87 m_udiToGDI[udi] = Battery(path, tag);
88 }
89 delete[] buffer;
90 }
91 }
92 }
93
94 SetupDiDestroyDeviceInfoList(hdev);
95 }
96 return udis;
97}
98
99const WinBattery::Battery WinBattery::batteryInfoFromUdi(const QString &udi)
100{
101 return m_udiToGDI[udi];
102}
103
104void WinBattery::powerChanged()
105{
106 const int old_charge = m_charge;
107 const int old_capacity = m_capacity;
108 const int old_cyleCount = m_cycleCount;
109 const Solid::Battery::ChargeState old_state = m_state;
110 const bool old_isPowerSupply = m_isPowerSupply;
111 const double old_energy = m_energy;
112 const double old_energyFull = m_energyFull;
113 const double old_energyFullDesign = m_energyFullDesign;
114 const double old_energyRate = m_energyRate;
115 const double old_voltage = m_voltage;
116
117 BATTERY_WAIT_STATUS batteryStatusQuery;
118 ZeroMemory(&batteryStatusQuery, sizeof(batteryStatusQuery));
119 Battery b = m_udiToGDI[m_device->udi()];
120 batteryStatusQuery.BatteryTag = b.second;
121 BATTERY_STATUS status = WinDeviceManager::getDeviceInfo<BATTERY_STATUS, BATTERY_WAIT_STATUS>(b.first, IOCTL_BATTERY_QUERY_STATUS, &batteryStatusQuery);
122
123 BATTERY_QUERY_INFORMATION batteryInformationQuery;
124 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
125 batteryInformationQuery.BatteryTag = b.second;
126 batteryInformationQuery.InformationLevel = BatteryInformation;
127 BATTERY_INFORMATION info =
128 WinDeviceManager::getDeviceInfo<BATTERY_INFORMATION, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery);
129
130 initSerial(b);
131 updateBatteryTemp(b);
132 updateTimeToEmpty(b);
133
134 m_isPowerSupply = !(status.PowerState & BATTERY_POWER_ON_LINE);
135
136 QString tech = QString::fromUtf8((const char *)info.Chemistry, 4);
137
138 if (tech == QLatin1String("LION") || tech == QLatin1String("LI-I")) {
139 m_technology = Solid::Battery::LithiumIon;
140 } else if (tech == QLatin1String("PBAC")) {
141 m_technology = Solid::Battery::LeadAcid;
142 } else if (tech == QLatin1String("NICD")) {
143 m_technology = Solid::Battery::NickelCadmium;
144 } else if (tech == QLatin1String("NIMH")) {
145 m_technology = Solid::Battery::NickelMetalHydride;
146 } else {
147 m_technology = Solid::Battery::UnknownTechnology;
148 }
149
150 m_energy = status.Capacity / 1000.0; // provided in mWh
151 m_energyFull = info.FullChargedCapacity / 1000.0; // provided in mWh
152 m_energyFullDesign = info.DesignedCapacity / 1000.0; // provided in mWh
153 m_energyRate = status.Rate / 1000.0; // provided in mW
154 m_voltage = status.Voltage / 1000.0; // provided in mV
155
156 if (info.FullChargedCapacity != 0) {
157 m_charge = (float)status.Capacity / info.FullChargedCapacity * 100.0;
158 }
159
160 if (info.DesignedCapacity != 0) {
161 m_capacity = (float)info.FullChargedCapacity / info.DesignedCapacity * 100.0;
162 }
163
164 if (info.CycleCount != 0) {
165 m_cycleCount = info.CycleCount;
166 }
167
168 if (status.PowerState == 0) {
169 m_state = Solid::Battery::NoCharge;
170 } else if (status.PowerState & BATTERY_CHARGING) {
171 m_state = Solid::Battery::Charging;
172 } else if (status.PowerState & BATTERY_DISCHARGING) {
173 m_state = Solid::Battery::Discharging;
174 }
175 // else if(info.PowerState & 0x00000008)//critical
176 // {
177
178 // }
179
180 if (info.Capabilities & BATTERY_SYSTEM_BATTERY) {
181 m_type = Solid::Battery::PrimaryBattery;
182 } else {
183 m_type = Solid::Battery::UnknownBattery;
184 }
185
186 m_rechargeable = info.Technology == 1;
187
188 if (m_charge != old_charge) {
189 Q_EMIT chargePercentChanged(m_charge, m_device->udi());
190 }
191
192 if (m_capacity != old_capacity) {
193 Q_EMIT capacityChanged(m_capacity, m_device->udi());
194 }
195
196 if (m_cycleCount != old_cyleCount) {
197 Q_EMIT cycleCountChanged(m_cycleCount, m_device->udi());
198 }
199
200 if (old_state != m_state) {
201 Q_EMIT chargeStateChanged(m_state, m_device->udi());
202 }
203
204 if (old_isPowerSupply != m_isPowerSupply) {
205 Q_EMIT powerSupplyStateChanged(m_isPowerSupply, m_device->udi());
206 }
207
208 if (old_energy != m_energy) {
209 Q_EMIT energyChanged(m_energy, m_device->udi());
210 }
211
212 if (old_energyFull != m_energyFull) {
213 Q_EMIT energyFullChanged(m_energyFull, m_device->udi());
214 }
215
216 if (old_energyFullDesign != m_energyFullDesign) {
217 Q_EMIT energyFullDesignChanged(m_energyFullDesign, m_device->udi());
218 }
219
220 if (old_energyRate != m_energyRate) {
221 Q_EMIT energyRateChanged(m_energyRate, m_device->udi());
222 }
223
224 if (old_voltage != m_voltage) {
225 Q_EMIT voltageChanged(m_voltage, m_device->udi());
226 }
227}
228
229void WinBattery::initSerial(const Battery &b)
230{
231 wchar_t buffer[1024];
232 BATTERY_QUERY_INFORMATION batteryInformationQuery;
233 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
234 batteryInformationQuery.BatteryTag = b.second;
235 batteryInformationQuery.InformationLevel = BatterySerialNumber;
236 WinDeviceManager::getDeviceInfo<wchar_t, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, buffer, 1024, &batteryInformationQuery);
237
238 m_serial = QString::fromWCharArray(buffer);
239}
240
241void WinBattery::updateTimeToEmpty(const WinBattery::Battery &b)
242{
243 BATTERY_QUERY_INFORMATION batteryInformationQuery;
244 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
245 batteryInformationQuery.BatteryTag = b.second;
246 batteryInformationQuery.InformationLevel = BatteryEstimatedTime;
247 ulong time = WinDeviceManager::getDeviceInfo<ulong, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery);
248
249 if (time == BATTERY_UNKNOWN_TIME) {
250 time = 0;
251 }
252
253 if (time != m_timeUntilEmpty) {
254 m_timeUntilEmpty = time;
255 Q_EMIT timeToEmptyChanged(time, m_device->udi());
256 }
257}
258
259void WinBattery::updateBatteryTemp(const WinBattery::Battery &b)
260{
261 BATTERY_QUERY_INFORMATION batteryInformationQuery;
262 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery));
263 batteryInformationQuery.BatteryTag = b.second;
264 batteryInformationQuery.InformationLevel = BatteryTemperature;
265 ulong batteryTemp = WinDeviceManager::getDeviceInfo<ulong, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery);
266
267 if (batteryTemp != m_temperature) {
268 m_temperature = batteryTemp;
269 Q_EMIT temperatureChanged(batteryTemp, m_device->udi());
270 }
271}
272
273Solid::Battery::Technology WinBattery::technology() const
274{
275 return m_technology;
276}
277
278double WinBattery::energy() const
279{
280 return m_energy;
281}
282
283double WinBattery::energyFull() const
284{
285 return m_energyFull;
286}
287
288double WinBattery::energyFullDesign() const
289{
290 return m_energyFullDesign;
291}
292
293double WinBattery::energyRate() const
294{
295 return m_energyRate;
296}
297
298double WinBattery::voltage() const
299{
300 return m_voltage;
301}
302
303bool WinBattery::isPresent() const
304{
305 return true;
306}
307
308qlonglong WinBattery::timeToEmpty() const
309{
310 return m_timeUntilEmpty;
311}
312
313qlonglong WinBattery::timeToFull() const
314{
315 return 0;
316}
317
318double WinBattery::temperature() const
319{
320 return m_temperature;
321}
322
323qlonglong WinBattery::remainingTime() const
324{
325 return m_timeUntilEmpty; // FIXME
326}
327
328QString WinBattery::serial() const
329{
330 return m_serial;
331}
332
333#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)
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 Fri Nov 22 2024 12:01:49 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.