File indexing completed on 2024-05-26 04:05:39
0001 /* 0002 SPDX-FileCopyrightText: 2013 Patrick von Reth <vonreth@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 #include "winbattery.h" 0007 #include "windevicemanager_p.h" 0008 0009 #include <batclass.h> 0010 #include <devguid.h> 0011 #include <devpropdef.h> 0012 #include <setupapi.h> 0013 0014 using namespace Solid::Backends::Win; 0015 0016 QMap<QString, WinBattery::Battery> WinBattery::m_udiToGDI = QMap<QString, WinBattery::Battery>(); 0017 0018 WinBattery::WinBattery(WinDevice *device) 0019 : WinInterface(device) 0020 , m_state(Solid::Battery::NoCharge) 0021 { 0022 powerChanged(); 0023 connect(SolidWinEventFilter::instance(), SIGNAL(powerChanged()), this, SLOT(powerChanged())); 0024 } 0025 0026 Solid::Battery::BatteryType WinBattery::type() const 0027 { 0028 return m_type; 0029 } 0030 0031 int WinBattery::chargePercent() const 0032 { 0033 return m_charge; 0034 } 0035 0036 int WinBattery::capacity() const 0037 { 0038 return m_capacity; 0039 } 0040 0041 bool WinBattery::isRechargeable() const 0042 { 0043 return m_rechargeable; 0044 } 0045 0046 bool WinBattery::isPowerSupply() const 0047 { 0048 return m_isPowerSupply; 0049 } 0050 0051 Solid::Battery::ChargeState WinBattery::chargeState() const 0052 { 0053 return m_state; 0054 } 0055 0056 QSet<QString> WinBattery::getUdis() 0057 { 0058 QSet<QString> udis; 0059 HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 0060 0061 if (INVALID_HANDLE_VALUE != hdev) { 0062 // Limit search to 100 batteries max 0063 for (int idev = 0; idev < 100; idev++) { 0064 SP_DEVICE_INTERFACE_DATA did; 0065 ZeroMemory(&did, sizeof(did)); 0066 did.cbSize = sizeof(did); 0067 0068 if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVCLASS_BATTERY, idev, &did)) { 0069 DWORD cbRequired = 0; 0070 0071 SetupDiGetDeviceInterfaceDetailW(hdev, &did, 0, 0, &cbRequired, 0); 0072 if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { 0073 char *buffer = new char[cbRequired]; 0074 SP_DEVICE_INTERFACE_DETAIL_DATA *pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA *)buffer; 0075 ZeroMemory(pdidd, cbRequired); 0076 pdidd->cbSize = sizeof(*pdidd); 0077 if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0)) { 0078 QString path = QString::fromWCharArray(pdidd->DevicePath); 0079 ulong tag = WinDeviceManager::getDeviceInfo<ulong>(path, IOCTL_BATTERY_QUERY_TAG); 0080 QString udi = QLatin1String("/org/kde/solid/win/power.battery/battery#") + QString::number(tag); 0081 udis << udi; 0082 m_udiToGDI[udi] = Battery(path, tag); 0083 } 0084 delete[] buffer; 0085 } 0086 } 0087 } 0088 0089 SetupDiDestroyDeviceInfoList(hdev); 0090 } 0091 return udis; 0092 } 0093 0094 const WinBattery::Battery WinBattery::batteryInfoFromUdi(const QString &udi) 0095 { 0096 return m_udiToGDI[udi]; 0097 } 0098 0099 void WinBattery::powerChanged() 0100 { 0101 const int old_charge = m_charge; 0102 const int old_capacity = m_capacity; 0103 const Solid::Battery::ChargeState old_state = m_state; 0104 const bool old_isPowerSupply = m_isPowerSupply; 0105 const double old_energy = m_energy; 0106 const double old_energyFull = m_energyFull; 0107 const double old_energyFullDesign = m_energyFullDesign; 0108 const double old_energyRate = m_energyRate; 0109 const double old_voltage = m_voltage; 0110 0111 BATTERY_WAIT_STATUS batteryStatusQuery; 0112 ZeroMemory(&batteryStatusQuery, sizeof(batteryStatusQuery)); 0113 Battery b = m_udiToGDI[m_device->udi()]; 0114 batteryStatusQuery.BatteryTag = b.second; 0115 BATTERY_STATUS status = WinDeviceManager::getDeviceInfo<BATTERY_STATUS, BATTERY_WAIT_STATUS>(b.first, IOCTL_BATTERY_QUERY_STATUS, &batteryStatusQuery); 0116 0117 BATTERY_QUERY_INFORMATION batteryInformationQuery; 0118 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery)); 0119 batteryInformationQuery.BatteryTag = b.second; 0120 batteryInformationQuery.InformationLevel = BatteryInformation; 0121 BATTERY_INFORMATION info = 0122 WinDeviceManager::getDeviceInfo<BATTERY_INFORMATION, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery); 0123 0124 initSerial(b); 0125 updateBatteryTemp(b); 0126 updateTimeToEmpty(b); 0127 0128 m_isPowerSupply = !(status.PowerState & BATTERY_POWER_ON_LINE); 0129 0130 QString tech = QString::fromUtf8((const char *)info.Chemistry, 4); 0131 0132 if (tech == "LION" || tech == "LI-I") { 0133 m_technology = Solid::Battery::LithiumIon; 0134 } else if (tech == "PBAC") { 0135 m_technology = Solid::Battery::LeadAcid; 0136 } else if (tech == "NICD") { 0137 m_technology = Solid::Battery::NickelCadmium; 0138 } else if (tech == "NIMH") { 0139 m_technology = Solid::Battery::NickelMetalHydride; 0140 } else { 0141 m_technology = Solid::Battery::UnknownTechnology; 0142 } 0143 0144 m_energy = status.Capacity / 1000.0; // provided in mWh 0145 m_energyFull = info.FullChargedCapacity / 1000.0; // provided in mWh 0146 m_energyFullDesign = info.DesignedCapacity / 1000.0; // provided in mWh 0147 m_energyRate = status.Rate / 1000.0; // provided in mW 0148 m_voltage = status.Voltage / 1000.0; // provided in mV 0149 0150 if (info.FullChargedCapacity != 0) { 0151 m_charge = (float)status.Capacity / info.FullChargedCapacity * 100.0; 0152 } 0153 0154 if (info.DesignedCapacity != 0) { 0155 m_capacity = (float)info.FullChargedCapacity / info.DesignedCapacity * 100.0; 0156 } 0157 0158 if (status.PowerState == 0) { 0159 m_state = Solid::Battery::NoCharge; 0160 } else if (status.PowerState & BATTERY_CHARGING) { 0161 m_state = Solid::Battery::Charging; 0162 } else if (status.PowerState & BATTERY_DISCHARGING) { 0163 m_state = Solid::Battery::Discharging; 0164 } 0165 // else if(info.PowerState & 0x00000008)//critical 0166 // { 0167 0168 // } 0169 0170 if (info.Capabilities & BATTERY_SYSTEM_BATTERY) { 0171 m_type = Solid::Battery::PrimaryBattery; 0172 } else { 0173 m_type = Solid::Battery::UnknownBattery; 0174 } 0175 0176 m_rechargeable = info.Technology == 1; 0177 0178 if (m_charge != old_charge) { 0179 Q_EMIT chargePercentChanged(m_charge, m_device->udi()); 0180 } 0181 0182 if (m_capacity != old_capacity) { 0183 Q_EMIT capacityChanged(m_capacity, m_device->udi()); 0184 } 0185 0186 if (old_state != m_state) { 0187 Q_EMIT chargeStateChanged(m_state, m_device->udi()); 0188 } 0189 0190 if (old_isPowerSupply != m_isPowerSupply) { 0191 Q_EMIT powerSupplyStateChanged(m_isPowerSupply, m_device->udi()); 0192 } 0193 0194 if (old_energy != m_energy) { 0195 Q_EMIT energyChanged(m_energy, m_device->udi()); 0196 } 0197 0198 if (old_energyFull != m_energyFull) { 0199 Q_EMIT energyFullChanged(m_energyFull, m_device->udi()); 0200 } 0201 0202 if (old_energyFullDesign != m_energyFullDesign) { 0203 Q_EMIT energyFullDesignChanged(m_energyFullDesign, m_device->udi()); 0204 } 0205 0206 if (old_energyRate != m_energyRate) { 0207 Q_EMIT energyRateChanged(m_energyRate, m_device->udi()); 0208 } 0209 0210 if (old_voltage != m_voltage) { 0211 Q_EMIT voltageChanged(m_voltage, m_device->udi()); 0212 } 0213 } 0214 0215 void WinBattery::initSerial(const Battery &b) 0216 { 0217 wchar_t buffer[1024]; 0218 BATTERY_QUERY_INFORMATION batteryInformationQuery; 0219 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery)); 0220 batteryInformationQuery.BatteryTag = b.second; 0221 batteryInformationQuery.InformationLevel = BatterySerialNumber; 0222 WinDeviceManager::getDeviceInfo<wchar_t, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, buffer, 1024, &batteryInformationQuery); 0223 0224 m_serial = QString::fromWCharArray(buffer); 0225 } 0226 0227 void WinBattery::updateTimeToEmpty(const WinBattery::Battery &b) 0228 { 0229 BATTERY_QUERY_INFORMATION batteryInformationQuery; 0230 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery)); 0231 batteryInformationQuery.BatteryTag = b.second; 0232 batteryInformationQuery.InformationLevel = BatteryEstimatedTime; 0233 ulong time = WinDeviceManager::getDeviceInfo<ulong, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery); 0234 0235 if (time == BATTERY_UNKNOWN_TIME) { 0236 time = 0; 0237 } 0238 0239 if (time != m_timeUntilEmpty) { 0240 m_timeUntilEmpty = time; 0241 Q_EMIT timeToEmptyChanged(time, m_device->udi()); 0242 } 0243 } 0244 0245 void WinBattery::updateBatteryTemp(const WinBattery::Battery &b) 0246 { 0247 BATTERY_QUERY_INFORMATION batteryInformationQuery; 0248 ZeroMemory(&batteryInformationQuery, sizeof(batteryInformationQuery)); 0249 batteryInformationQuery.BatteryTag = b.second; 0250 batteryInformationQuery.InformationLevel = BatteryTemperature; 0251 ulong batteryTemp = WinDeviceManager::getDeviceInfo<ulong, BATTERY_QUERY_INFORMATION>(b.first, IOCTL_BATTERY_QUERY_INFORMATION, &batteryInformationQuery); 0252 0253 if (batteryTemp != m_temperature) { 0254 m_temperature = batteryTemp; 0255 Q_EMIT temperatureChanged(batteryTemp, m_device->udi()); 0256 } 0257 } 0258 0259 Solid::Battery::Technology WinBattery::technology() const 0260 { 0261 return m_technology; 0262 } 0263 0264 double WinBattery::energy() const 0265 { 0266 return m_energy; 0267 } 0268 0269 double WinBattery::energyFull() const 0270 { 0271 return m_energyFull; 0272 } 0273 0274 double WinBattery::energyFullDesign() const 0275 { 0276 return m_energyFullDesign; 0277 } 0278 0279 double WinBattery::energyRate() const 0280 { 0281 return m_energyRate; 0282 } 0283 0284 double WinBattery::voltage() const 0285 { 0286 return m_voltage; 0287 } 0288 0289 bool WinBattery::isPresent() const 0290 { 0291 return true; 0292 } 0293 0294 qlonglong WinBattery::timeToEmpty() const 0295 { 0296 return m_timeUntilEmpty; 0297 } 0298 0299 qlonglong WinBattery::timeToFull() const 0300 { 0301 return 0; 0302 } 0303 0304 double WinBattery::temperature() const 0305 { 0306 return m_temperature; 0307 } 0308 0309 qlonglong WinBattery::remainingTime() const 0310 { 0311 return m_timeUntilEmpty; // FIXME 0312 } 0313 0314 QString WinBattery::serial() const 0315 { 0316 return m_serial; 0317 } 0318 0319 #include "moc_winbattery.cpp"