1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). |
4 | ** Copyright (C) 2014 BlackBerry Limited. All rights reserved. |
5 | ** Contact: http://www.qt-project.org/legal |
6 | ** |
7 | ** This file is part of the QtSystems module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL21$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see http://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at http://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 2.1 or version 3 as published by the Free |
21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
23 | ** following information to ensure the GNU Lesser General Public License |
24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
26 | ** |
27 | ** As a special exception, The Qt Company gives you certain additional |
28 | ** rights. These rights are described in The Qt Company LGPL Exception |
29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
30 | ** |
31 | ** $QT_END_LICENSE$ |
32 | ** |
33 | ****************************************************************************/ |
34 | |
35 | #include "qbatteryinfo_linux_p.h" |
36 | |
37 | #include <QtCore/qdir.h> |
38 | #include <QtCore/qfile.h> |
39 | #include <QtCore/qmetaobject.h> |
40 | #include <QtCore/qtimer.h> |
41 | #include <QtCore/qnumeric.h> |
42 | |
43 | #if !defined(QT_NO_UDEV) |
44 | #include "qudevwrapper_p.h" |
45 | #endif // QT_NO_UDEV |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, AC_ONLINE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/AC/online" ))) |
50 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, BATTERY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/BAT%1/" ))) |
51 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, POWER_SUPPLY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/" ))) |
52 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB_PRESENT_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/usb/present" ))) |
53 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB_TYPE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/usb/type" ))) |
54 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB0_PRESENT_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/USB0/present" ))) |
55 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB0_TYPE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/USB0/type" ))) |
56 | |
57 | QBatteryInfoPrivate::QBatteryInfoPrivate(QBatteryInfo *parent) |
58 | : QObject(parent) |
59 | , q_ptr(parent) |
60 | , watchIsValid(false) |
61 | , forceWatchBatteryCount(false) |
62 | , watchBatteryCount(false) |
63 | , watchChargerType(false) |
64 | , watchChargingState(false) |
65 | , watchCurrentFlow(false) |
66 | , watchRemainingCapacity(false) |
67 | , watchRemainingChargingTime(false) |
68 | , watchVoltage(false) |
69 | , watchLevelStatus(false) |
70 | , batteryCounts(-1) |
71 | , index(0) |
72 | , currentChargerType(QBatteryInfo::UnknownCharger) |
73 | #if !defined(QT_NO_UDEV) |
74 | , uDevWrapper(0) |
75 | #else |
76 | , timer(0) |
77 | #endif // QT_NO_UDEV |
78 | { |
79 | } |
80 | |
81 | QBatteryInfoPrivate::QBatteryInfoPrivate(int batteryIndex, QBatteryInfo *parent) |
82 | : QObject(parent) |
83 | , q_ptr(parent) |
84 | , watchIsValid(false) |
85 | , forceWatchBatteryCount(false) |
86 | , watchBatteryCount(false) |
87 | , watchChargerType(false) |
88 | , watchChargingState(false) |
89 | , watchCurrentFlow(false) |
90 | , watchRemainingCapacity(false) |
91 | , watchRemainingChargingTime(false) |
92 | , watchVoltage(false) |
93 | , watchLevelStatus(false) |
94 | , batteryCounts(-1) |
95 | , index(batteryIndex) |
96 | , currentChargerType(QBatteryInfo::UnknownCharger) |
97 | #if !defined(QT_NO_UDEV) |
98 | , uDevWrapper(0) |
99 | #else |
100 | , timer(0) |
101 | #endif // QT_NO_UDEV |
102 | { |
103 | } |
104 | |
105 | QBatteryInfoPrivate::~QBatteryInfoPrivate() |
106 | { |
107 | #if defined(QT_NO_UDEV) |
108 | delete timer; |
109 | #endif // QT_NO_UDEV |
110 | } |
111 | |
112 | int QBatteryInfoPrivate::batteryCount() |
113 | { |
114 | if (!watchBatteryCount) |
115 | return getBatteryCount(); |
116 | |
117 | return batteryCounts; |
118 | } |
119 | |
120 | int QBatteryInfoPrivate::batteryIndex() const |
121 | { |
122 | return index; |
123 | } |
124 | |
125 | bool QBatteryInfoPrivate::isValid() |
126 | { |
127 | // valid if the index < total count. |
128 | return (index >= 0) && (index < batteryCount()); |
129 | } |
130 | |
131 | void QBatteryInfoPrivate::setBatteryIndex(int batteryIndex) |
132 | { |
133 | if (index != batteryIndex) { |
134 | bool validBefore = isValid(); |
135 | int oldIndex = index; |
136 | index = batteryIndex; |
137 | bool validNow = isValid(); |
138 | if (validBefore != validNow) |
139 | Q_EMIT validChanged(isValid: validNow); |
140 | |
141 | if (validNow) { |
142 | if (validBefore) { |
143 | // valid now, valid before so we have to check individual values |
144 | |
145 | // ignore chargerType - it won't change based on battery index |
146 | //emit chargerTypeChanged(newChargerType); |
147 | |
148 | QBatteryInfo::ChargingState newChargingState = chargingState(); |
149 | if (newChargingState != chargingState(battery: oldIndex)) |
150 | emit chargingStateChanged(state: newChargingState); |
151 | |
152 | int newValue = level(); |
153 | if (newValue != level(battery: oldIndex)) |
154 | emit levelChanged(level: newValue); |
155 | |
156 | newValue = currentFlow(); |
157 | if (newValue != currentFlow(battery: oldIndex)) |
158 | emit currentFlowChanged(flow: newValue); |
159 | |
160 | newValue = cycleCount(); |
161 | if (newValue != cycleCount(battery: oldIndex)) |
162 | emit cycleCountChanged(cycleCount: newValue); |
163 | |
164 | newValue = remainingCapacity(); |
165 | if (newValue != remainingCapacity(battery: oldIndex)) |
166 | emit remainingCapacityChanged(capacity: newValue); |
167 | |
168 | newValue = remainingChargingTime(); |
169 | if (newValue != remainingChargingTime(battery: oldIndex)) |
170 | emit remainingChargingTimeChanged(seconds: newValue); |
171 | |
172 | newValue = voltage(); |
173 | if (newValue != voltage(battery: oldIndex)) |
174 | emit voltageChanged(voltage: newValue); |
175 | |
176 | QBatteryInfo::LevelStatus newLevelStatus = levelStatus(); |
177 | if (newLevelStatus != levelStatus(battery: oldIndex)) |
178 | emit levelStatusChanged(levelStatus: newLevelStatus); |
179 | |
180 | QBatteryInfo::Health newHealth = health(); |
181 | if (newHealth != health(battery: oldIndex)) |
182 | emit healthChanged(health: newHealth); |
183 | |
184 | float newTemperature = temperature(); |
185 | if (!qFuzzyCompare(p1: newTemperature, p2: temperature(battery: oldIndex))) |
186 | emit temperatureChanged(temperature: newTemperature); |
187 | } else { |
188 | // it wasn't valid before so everything is changed |
189 | |
190 | // ignore chargerType - it won't change based on battery index |
191 | //emit chargerTypeChanged(newChargerType); |
192 | |
193 | emit chargingStateChanged(state: chargingState()); |
194 | emit levelChanged(level: level()); |
195 | emit currentFlowChanged(flow: currentFlow()); |
196 | emit cycleCountChanged(cycleCount: cycleCount()); |
197 | emit remainingCapacityChanged(capacity: remainingCapacity()); |
198 | emit remainingChargingTimeChanged(seconds: remainingChargingTime()); |
199 | emit voltageChanged(voltage: voltage()); |
200 | emit levelStatusChanged(levelStatus: levelStatus()); |
201 | emit healthChanged(health: health()); |
202 | emit temperatureChanged(temperature: temperature()); |
203 | } |
204 | } |
205 | |
206 | emit batteryIndexChanged(batteryIndex: index); |
207 | } |
208 | } |
209 | |
210 | int QBatteryInfoPrivate::level(int battery) |
211 | { |
212 | int maxCapacity = maximumCapacity(battery); |
213 | int remCapacity = remainingCapacity(battery); |
214 | |
215 | if (maxCapacity == 0) |
216 | return -1; |
217 | |
218 | return remCapacity * 100 / maxCapacity; |
219 | } |
220 | |
221 | int QBatteryInfoPrivate::level() |
222 | { |
223 | return level(battery: index); |
224 | } |
225 | |
226 | int QBatteryInfoPrivate::currentFlow(int battery) |
227 | { |
228 | if (!watchCurrentFlow) |
229 | return getCurrentFlow(battery); |
230 | |
231 | return currentFlows.value(akey: battery); |
232 | } |
233 | |
234 | int QBatteryInfoPrivate::currentFlow() |
235 | { |
236 | return currentFlow(battery: index); |
237 | } |
238 | |
239 | int QBatteryInfoPrivate::cycleCount(int battery) |
240 | { |
241 | Q_UNUSED(battery) |
242 | |
243 | return -1; |
244 | } |
245 | |
246 | int QBatteryInfoPrivate::cycleCount() |
247 | { |
248 | return cycleCount(battery: index); |
249 | } |
250 | |
251 | int QBatteryInfoPrivate::maximumCapacity(int battery) |
252 | { |
253 | if (maximumCapacities[battery] == 0) { |
254 | QFile maximum(BATTERY_SYSFS_PATH()->arg(a: battery) + QStringLiteral("charge_full" )); |
255 | if (maximum.open(flags: QIODevice::ReadOnly)) { |
256 | bool ok = false; |
257 | int capacity = maximum.readAll().simplified().toInt(ok: &ok); |
258 | if (ok) |
259 | maximumCapacities[battery] = capacity / 1000; |
260 | else |
261 | maximumCapacities[battery] = -1; |
262 | } else { |
263 | maximumCapacities[battery] = -1; |
264 | } |
265 | } |
266 | |
267 | return maximumCapacities[battery]; |
268 | } |
269 | |
270 | int QBatteryInfoPrivate::maximumCapacity() |
271 | { |
272 | return maximumCapacity(battery: index); |
273 | } |
274 | |
275 | int QBatteryInfoPrivate::remainingCapacity(int battery) |
276 | { |
277 | if (!watchRemainingCapacity) |
278 | return getRemainingCapacity(battery); |
279 | |
280 | return remainingCapacities.value(akey: battery); |
281 | } |
282 | |
283 | int QBatteryInfoPrivate::remainingCapacity() |
284 | { |
285 | return remainingCapacity(battery: index); |
286 | } |
287 | |
288 | int QBatteryInfoPrivate::remainingChargingTime(int battery) |
289 | { |
290 | if (!watchRemainingChargingTime) |
291 | return getRemainingChargingTime(battery); |
292 | |
293 | return remainingChargingTimes.value(akey: battery); |
294 | } |
295 | |
296 | int QBatteryInfoPrivate::remainingChargingTime() |
297 | { |
298 | return remainingChargingTime(battery: index); |
299 | } |
300 | |
301 | int QBatteryInfoPrivate::voltage(int battery) |
302 | { |
303 | if (!watchVoltage) |
304 | return getVoltage(battery); |
305 | |
306 | return voltages.value(akey: battery); |
307 | } |
308 | |
309 | int QBatteryInfoPrivate::voltage() |
310 | { |
311 | return voltage(battery: index); |
312 | } |
313 | |
314 | QBatteryInfo::ChargerType QBatteryInfoPrivate::chargerType() |
315 | { |
316 | if (!watchChargerType) |
317 | return getChargerType(); |
318 | |
319 | return currentChargerType; |
320 | } |
321 | |
322 | QBatteryInfo::ChargingState QBatteryInfoPrivate::chargingState(int battery) |
323 | { |
324 | if (!watchChargingState) |
325 | return getChargingState(battery); |
326 | |
327 | return chargingStates.value(akey: battery); |
328 | } |
329 | |
330 | QBatteryInfo::ChargingState QBatteryInfoPrivate::chargingState() |
331 | { |
332 | return chargingState(battery: index); |
333 | } |
334 | |
335 | QBatteryInfo::LevelStatus QBatteryInfoPrivate::levelStatus(int battery) |
336 | { |
337 | if (!watchLevelStatus) |
338 | return getLevelStatus(battery); |
339 | |
340 | return levelStatuss.value(akey: battery); |
341 | } |
342 | |
343 | QBatteryInfo::LevelStatus QBatteryInfoPrivate::levelStatus() |
344 | { |
345 | return levelStatus(battery: index); |
346 | } |
347 | |
348 | QBatteryInfo::Health QBatteryInfoPrivate::health(int battery) |
349 | { |
350 | Q_UNUSED(battery) |
351 | |
352 | return QBatteryInfo::HealthUnknown; |
353 | } |
354 | |
355 | QBatteryInfo::Health QBatteryInfoPrivate::health() |
356 | { |
357 | return health(battery: index); |
358 | } |
359 | |
360 | float QBatteryInfoPrivate::temperature(int battery) |
361 | { |
362 | Q_UNUSED(battery) |
363 | |
364 | return qQNaN(); |
365 | } |
366 | |
367 | float QBatteryInfoPrivate::temperature() |
368 | { |
369 | return temperature(battery: index); |
370 | } |
371 | |
372 | void QBatteryInfoPrivate::connectNotify(const QMetaMethod &signal) |
373 | { |
374 | static const QMetaMethod batteryCountChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::batteryCountChanged); |
375 | static const QMetaMethod validChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::validChanged); |
376 | static const QMetaMethod chargerTypeChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::chargerTypeChanged); |
377 | static const QMetaMethod chargingStateChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::chargingStateChanged); |
378 | static const QMetaMethod currentFlowChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::currentFlowChanged); |
379 | static const QMetaMethod remainingCapacityChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::remainingCapacityChanged); |
380 | static const QMetaMethod remainingChargingTimeChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::remainingChargingTimeChanged); |
381 | static const QMetaMethod voltageChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::voltageChanged); |
382 | static const QMetaMethod levelStatusChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::levelStatusChanged); |
383 | |
384 | #if !defined(QT_NO_UDEV) |
385 | if (!uDevWrapper) |
386 | uDevWrapper = new QUDevWrapper(this); |
387 | if (!watchChargerType && signal == chargerTypeChangedSignal) { |
388 | connect(uDevWrapper, SIGNAL(chargerTypeChanged(QByteArray,bool)), this, SLOT(onChargerTypeChanged(QByteArray,bool))); |
389 | } else if (!watchIsValid && !watchCurrentFlow && !watchVoltage && !watchChargingState && !watchRemainingCapacity |
390 | && !watchRemainingChargingTime && !watchBatteryCount && !watchLevelStatus) { |
391 | connect(uDevWrapper, SIGNAL(batteryDataChanged(int,QByteArray,QByteArray)), this, SLOT(onBatteryDataChanged(int,QByteArray,QByteArray))); |
392 | } |
393 | #else |
394 | if (timer == 0) { |
395 | timer = new QTimer; |
396 | timer->setInterval(2000); |
397 | connect(sender: timer, SIGNAL(timeout()), receiver: this, SLOT(onTimeout())); |
398 | } |
399 | |
400 | if (!timer->isActive()) |
401 | timer->start(); |
402 | #endif // QT_NO_UDEV |
403 | |
404 | if (signal == validChangedSignal) { |
405 | if (!watchIsValid && !watchBatteryCount) |
406 | forceWatchBatteryCount = true; |
407 | |
408 | watchIsValid = true; |
409 | |
410 | // we have to watch battery count if someone is watching validChanged. |
411 | watchBatteryCount = true; |
412 | batteryCounts = getBatteryCount(); |
413 | } else if (signal == batteryCountChangedSignal) { |
414 | watchBatteryCount = true; |
415 | forceWatchBatteryCount = false; |
416 | batteryCounts = getBatteryCount(); |
417 | } else if (signal == currentFlowChangedSignal) { |
418 | watchCurrentFlow = true; |
419 | int count = batteryCount(); |
420 | for (int i = 0; i < count; ++i) |
421 | currentFlows[i] = getCurrentFlow(battery: i); |
422 | } else if (signal == voltageChangedSignal) { |
423 | watchVoltage = true; |
424 | int count = batteryCount(); |
425 | for (int i = 0; i < count; ++i) |
426 | voltages[i] = getVoltage(battery: i); |
427 | } else if (signal == remainingCapacityChangedSignal) { |
428 | watchRemainingCapacity = true; |
429 | int count = batteryCount(); |
430 | for (int i = 0; i < count; ++i) |
431 | remainingCapacities[i] = getRemainingCapacity(battery: i); |
432 | } else if (signal == remainingChargingTimeChangedSignal) { |
433 | watchRemainingChargingTime = true; |
434 | int count = batteryCount(); |
435 | for (int i = 0; i < count; ++i) |
436 | remainingChargingTimes[i] = getRemainingChargingTime(battery: i); |
437 | } else if (signal == chargerTypeChangedSignal) { |
438 | watchChargerType = true; |
439 | currentChargerType = getChargerType(); |
440 | } else if (signal == chargingStateChangedSignal) { |
441 | watchChargingState = true; |
442 | int count = batteryCount(); |
443 | for (int i = 0; i < count; ++i) |
444 | chargingStates[i] = getChargingState(battery: i); |
445 | } else if (signal == levelStatusChangedSignal) { |
446 | watchLevelStatus = true; |
447 | int count = batteryCount(); |
448 | for (int i = 0; i < count; i++) |
449 | levelStatuss[i] = getLevelStatus(battery: i); |
450 | } |
451 | } |
452 | |
453 | void QBatteryInfoPrivate::disconnectNotify(const QMetaMethod &signal) |
454 | { |
455 | static const QMetaMethod batteryCountChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::batteryCountChanged); |
456 | static const QMetaMethod validChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::validChanged); |
457 | static const QMetaMethod chargerTypeChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::chargerTypeChanged); |
458 | static const QMetaMethod chargingStateChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::chargingStateChanged); |
459 | static const QMetaMethod currentFlowChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::currentFlowChanged); |
460 | static const QMetaMethod remainingCapacityChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::remainingCapacityChanged); |
461 | static const QMetaMethod remainingChargingTimeChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::remainingChargingTimeChanged); |
462 | static const QMetaMethod voltageChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::voltageChanged); |
463 | static const QMetaMethod levelStatusChangedSignal = QMetaMethod::fromSignal(signal: &QBatteryInfoPrivate::levelStatusChanged); |
464 | |
465 | if (signal == validChangedSignal) { |
466 | watchIsValid = false; |
467 | if (forceWatchBatteryCount) { |
468 | watchBatteryCount = false; |
469 | batteryCounts = -1; |
470 | } |
471 | } else if (signal == batteryCountChangedSignal) { |
472 | if (!watchIsValid) { |
473 | watchBatteryCount = false; |
474 | batteryCounts = -1; |
475 | } else { |
476 | forceWatchBatteryCount = true; |
477 | } |
478 | } else if (signal == currentFlowChangedSignal) { |
479 | watchCurrentFlow = false; |
480 | currentFlows.clear(); |
481 | } else if (signal == voltageChangedSignal) { |
482 | watchVoltage = false; |
483 | voltages.clear(); |
484 | } else if (signal == remainingCapacityChangedSignal) { |
485 | watchRemainingCapacity = false; |
486 | remainingCapacities.clear(); |
487 | } else if (signal == remainingChargingTimeChangedSignal) { |
488 | watchRemainingChargingTime = false; |
489 | remainingChargingTimes.clear(); |
490 | } else if (signal == chargerTypeChangedSignal) { |
491 | watchChargerType = false; |
492 | currentChargerType = QBatteryInfo::UnknownCharger; |
493 | } else if (signal == chargingStateChangedSignal) { |
494 | watchChargingState = false; |
495 | chargingStates.clear(); |
496 | } else if (signal == levelStatusChangedSignal) { |
497 | watchLevelStatus = false; |
498 | levelStatuss.clear(); |
499 | } |
500 | |
501 | #if !defined(QT_NO_UDEV) |
502 | if (uDevWrapper && !watchChargerType && signal == chargerTypeChangedSignal) { |
503 | disconnect(uDevWrapper, SIGNAL(chargerTypeChanged(QByteArray,bool)), |
504 | this, SLOT(onChargerTypeChanged(QByteArray,bool))); |
505 | } else if (uDevWrapper && !watchCurrentFlow && !watchVoltage && !watchChargingState && !watchRemainingCapacity |
506 | && !watchRemainingChargingTime && !watchBatteryCount && !watchLevelStatus) { |
507 | disconnect(uDevWrapper, SIGNAL(batteryDataChanged(int,QByteArray,QByteArray)), |
508 | this, SLOT(onBatteryDataChanged(int,QByteArray,QByteArray))); |
509 | } |
510 | #endif |
511 | |
512 | if (!watchBatteryCount && !watchChargerType && !watchChargingState |
513 | && !watchCurrentFlow && !watchRemainingCapacity |
514 | && !watchRemainingChargingTime && !watchVoltage && !watchLevelStatus) { |
515 | #if !defined(QT_NO_UDEV) |
516 | if (uDevWrapper) { |
517 | delete uDevWrapper; |
518 | uDevWrapper = 0; |
519 | } |
520 | #else |
521 | timer->stop(); |
522 | #endif // QT_NO_UDEV |
523 | } |
524 | } |
525 | |
526 | #if !defined(QT_NO_UDEV) |
527 | |
528 | void QBatteryInfoPrivate::onBatteryDataChanged(int battery, const QByteArray &attribute, const QByteArray &value) |
529 | { |
530 | if (watchBatteryCount) { |
531 | int count = getBatteryCount(); |
532 | if (batteryCounts != count) { |
533 | bool validBefore = isValid(); |
534 | batteryCounts = count; |
535 | bool validNow = isValid(); |
536 | if (validBefore != validNow) |
537 | Q_EMIT validChanged(validNow); |
538 | |
539 | // We do not have to worry about firing all changed signals here. |
540 | // Each individual value will receive an onBatteryDataChanged() call |
541 | // and will fire a signal at that time. |
542 | |
543 | emit batteryCountChanged(count); |
544 | } |
545 | } |
546 | |
547 | if (watchChargingState && attribute.contains("status" )) { |
548 | QBatteryInfo::ChargingState state = QBatteryInfo::UnknownChargingState; |
549 | if (qstrcmp(value, "Charging" ) == 0) |
550 | state = QBatteryInfo::Charging; |
551 | else if (qstrcmp(value, "Not charging" ) == 0) |
552 | state = QBatteryInfo::IdleChargingState; |
553 | else if (qstrcmp(value, "Discharging" ) == 0) |
554 | state = QBatteryInfo::Discharging; |
555 | else if (qstrcmp(value, "Full" ) == 0) |
556 | state = QBatteryInfo::IdleChargingState; |
557 | if (chargingStates.value(battery) != state) { |
558 | chargingStates[battery] = state; |
559 | if (battery == index) |
560 | emit chargingStateChanged(state); |
561 | } |
562 | } |
563 | |
564 | if (watchRemainingCapacity && attribute.contains("charge_now" )) { |
565 | if (!value.isEmpty()) { |
566 | int remainingCapacity = value.toInt() / 1000; |
567 | if (remainingCapacities.value(battery) != remainingCapacity) { |
568 | remainingCapacities[battery] = remainingCapacity; |
569 | if (battery == index) |
570 | emit remainingCapacityChanged(remainingCapacity); |
571 | } |
572 | } |
573 | } |
574 | |
575 | if (watchRemainingChargingTime && attribute.contains("time_to_full_avg" )) { |
576 | if (!value.isEmpty()) { |
577 | int remainingChargingTime = value.toInt(); |
578 | if (remainingChargingTimes.value(battery) != remainingChargingTime) { |
579 | remainingChargingTimes[battery] = remainingChargingTime; |
580 | if (battery == index) |
581 | emit remainingChargingTimeChanged(remainingChargingTime); |
582 | } |
583 | } |
584 | } |
585 | |
586 | if (watchVoltage && attribute.contains("voltage_now" )) { |
587 | if (!value.isEmpty()) { |
588 | int voltage = value.toInt() / 1000; |
589 | if (voltages.value(battery) != voltage) { |
590 | voltages[battery] = voltage; |
591 | if (battery == index) |
592 | emit voltageChanged(voltage); |
593 | } |
594 | } |
595 | } |
596 | |
597 | if (watchCurrentFlow && attribute.contains("current_now" )) { |
598 | if (!value.isEmpty()) { |
599 | int currentFlow = value.toInt() / -1000; |
600 | if (chargingStates.value(battery) == QBatteryInfo::Discharging && currentFlow < 0) |
601 | currentFlow = -currentFlow; |
602 | |
603 | if (currentFlows.value(battery) != currentFlow) { |
604 | currentFlows[battery] = currentFlow; |
605 | if (battery == index) |
606 | emit currentFlowChanged(currentFlow); |
607 | } |
608 | } |
609 | } |
610 | |
611 | if (watchLevelStatus && attribute.contains("capacity_level" )) { |
612 | QBatteryInfo::LevelStatus levelStatus = QBatteryInfo::LevelUnknown; |
613 | if (qstrcmp(value, "Critical" ) == 0) |
614 | levelStatus = QBatteryInfo::LevelEmpty; |
615 | else if (qstrcmp(value, "Low" ) == 0) |
616 | levelStatus = QBatteryInfo::LevelLow; |
617 | else if (qstrcmp(value, "Normal" ) == 0) |
618 | levelStatus = QBatteryInfo::LevelOk; |
619 | else if (qstrcmp(value, "Full" ) == 0) |
620 | levelStatus = QBatteryInfo::LevelFull; |
621 | if (levelStatuss.value(battery) != levelStatus) { |
622 | levelStatuss[battery] = levelStatus; |
623 | if (battery == index) |
624 | emit levelStatusChanged(levelStatus); |
625 | } |
626 | } |
627 | } |
628 | |
629 | void QBatteryInfoPrivate::onChargerTypeChanged(const QByteArray &value, bool enabled) |
630 | { |
631 | if (watchChargerType) { |
632 | QBatteryInfo::ChargerType charger = QBatteryInfo::UnknownCharger; |
633 | if (enabled) { |
634 | if ((qstrcmp(value, "AC" ) == 0) || qstrcmp(value, "USB_DCP" ) == 0) |
635 | charger = QBatteryInfo::WallCharger; |
636 | else if (qstrcmp(value, "USB" ) == 0) |
637 | charger = QBatteryInfo::USBCharger; |
638 | else if (qstrcmp(value, "USB_CDP" ) == 0 || qstrcmp(value, "USB_SDP" ) == 0) |
639 | charger = QBatteryInfo::VariableCurrentCharger; |
640 | } |
641 | if (currentChargerType != charger) { |
642 | currentChargerType = charger; |
643 | emit chargerTypeChanged(charger); |
644 | } |
645 | } |
646 | } |
647 | |
648 | #else |
649 | |
650 | void QBatteryInfoPrivate::onTimeout() |
651 | { |
652 | int count = getBatteryCount(); |
653 | int value; |
654 | if (watchBatteryCount) { |
655 | value = getBatteryCount(); |
656 | if (batteryCounts != value) { |
657 | bool validBefore = isValid(); |
658 | batteryCounts = value; |
659 | bool validNow = isValid(); |
660 | if (validBefore != validNow) |
661 | Q_EMIT validChanged(isValid: validNow); |
662 | |
663 | // We do not have to worry about firing all changed signals here. |
664 | // Each individual value will (possibly) be updated below |
665 | // and will fire a signal at that time if it has changed. |
666 | |
667 | emit batteryCountChanged(count: value); |
668 | } |
669 | } |
670 | |
671 | for (int i = 0; i < count; ++i) { |
672 | if (watchCurrentFlow) { |
673 | value = getCurrentFlow(battery: i); |
674 | if (currentFlows.value(akey: i) != value) { |
675 | currentFlows[i] = value; |
676 | if (i == index) |
677 | emit currentFlowChanged(flow: value); |
678 | } |
679 | } |
680 | |
681 | if (watchVoltage) { |
682 | value = getVoltage(battery: i); |
683 | if (voltages.value(akey: i) != value) { |
684 | voltages[i] = value; |
685 | if (i == index) |
686 | emit voltageChanged(voltage: value); |
687 | } |
688 | } |
689 | |
690 | if (watchRemainingCapacity) { |
691 | value = getRemainingCapacity(battery: i); |
692 | if (remainingCapacities.value(akey: i) != value) { |
693 | remainingCapacities[i] = value; |
694 | if (i == index) |
695 | emit remainingCapacityChanged(capacity: value); |
696 | } |
697 | } |
698 | |
699 | if (watchRemainingChargingTime) { |
700 | value = getRemainingChargingTime(battery: i); |
701 | if (remainingChargingTimes.value(akey: i) != value) { |
702 | remainingChargingTimes[i] = value; |
703 | if (i == index) |
704 | emit remainingChargingTimeChanged(seconds: value); |
705 | } |
706 | } |
707 | |
708 | if (watchChargerType) { |
709 | QBatteryInfo::ChargerType charger = getChargerType(); |
710 | if (currentChargerType != charger) { |
711 | currentChargerType = charger; |
712 | emit chargerTypeChanged(type: charger); |
713 | } |
714 | } |
715 | |
716 | if (watchChargingState) { |
717 | QBatteryInfo::ChargingState state = getChargingState(battery: i); |
718 | if (chargingStates.value(akey: i) != state) { |
719 | chargingStates[i] = state; |
720 | if (i == index) |
721 | emit chargingStateChanged(state); |
722 | } |
723 | } |
724 | |
725 | if (watchLevelStatus) { |
726 | QBatteryInfo::LevelStatus levelStatus = getLevelStatus(battery: i); |
727 | if (levelStatuss.value(akey: i) != levelStatus) { |
728 | levelStatuss[i] = levelStatus; |
729 | if (i == index) |
730 | emit levelStatusChanged(levelStatus); |
731 | } |
732 | } |
733 | } |
734 | } |
735 | |
736 | #endif // QT_NO_UDEV |
737 | |
738 | int QBatteryInfoPrivate::getBatteryCount() |
739 | { |
740 | return QDir(*POWER_SUPPLY_SYSFS_PATH()).entryList(nameFilters: QStringList() << QStringLiteral("BAT*" )).size(); |
741 | } |
742 | |
743 | int QBatteryInfoPrivate::getCurrentFlow(int battery) |
744 | { |
745 | QBatteryInfo::ChargingState state = chargingState(battery); |
746 | if (state == QBatteryInfo::UnknownChargingState) |
747 | return 0; |
748 | |
749 | QFile current(BATTERY_SYSFS_PATH()->arg(a: battery) + QStringLiteral("current_now" )); |
750 | if (!current.open(flags: QIODevice::ReadOnly)) |
751 | return 0; |
752 | |
753 | bool ok = false; |
754 | int flow = current.readAll().simplified().toInt(ok: &ok); |
755 | if (ok) { |
756 | // We want discharging current to be positive and charging current to be negative. |
757 | if (state == QBatteryInfo::Charging) { |
758 | // In case some drivers make charging current negative already and others are opposite |
759 | return flow < 0 ? flow / 1000 : flow / -1000; |
760 | } else if (state == QBatteryInfo::Discharging) { |
761 | // In case some drivers make discharging current positive already and others are opposite |
762 | return flow > 0 ? flow / 1000 : flow / -1000; |
763 | } |
764 | } |
765 | |
766 | return 0; |
767 | } |
768 | |
769 | int QBatteryInfoPrivate::getRemainingCapacity(int battery) |
770 | { |
771 | QFile remaining(BATTERY_SYSFS_PATH()->arg(a: battery) + QStringLiteral("charge_now" )); |
772 | if (!remaining.open(flags: QIODevice::ReadOnly)) |
773 | return -1; |
774 | |
775 | bool ok = false; |
776 | int capacity = remaining.readAll().simplified().toInt(ok: &ok); |
777 | if (ok) |
778 | return capacity / 1000; |
779 | return -1; |
780 | } |
781 | |
782 | int QBatteryInfoPrivate::getRemainingChargingTime(int battery) |
783 | { |
784 | QBatteryInfo::ChargingState state = chargingState(battery); |
785 | if (state == QBatteryInfo::UnknownChargingState) |
786 | return -1; |
787 | else if (state == QBatteryInfo::IdleChargingState || state == QBatteryInfo::Discharging) |
788 | return 0; |
789 | |
790 | int remaining = 0; |
791 | QFile timeToFull(BATTERY_SYSFS_PATH()->arg(a: battery) + QStringLiteral("time_to_full_avg" )); |
792 | if (timeToFull.open(flags: QIODevice::ReadOnly)) { |
793 | bool ok = false; |
794 | remaining = timeToFull.readAll().simplified().toInt(ok: &ok); |
795 | if (ok) |
796 | return remaining; |
797 | return -1; |
798 | } |
799 | |
800 | int max = 0; |
801 | int current = 0; |
802 | if ((max = maximumCapacity(battery)) == -1 |
803 | || (remaining = remainingCapacity(battery)) == -1 |
804 | || (current = currentFlow(battery)) == 0) { |
805 | return -1; |
806 | } |
807 | return (max - remaining) * -3600 / current; |
808 | } |
809 | |
810 | int QBatteryInfoPrivate::getVoltage(int battery) |
811 | { |
812 | QFile current(BATTERY_SYSFS_PATH()->arg(a: battery) + QStringLiteral("voltage_now" )); |
813 | if (!current.open(flags: QIODevice::ReadOnly)) |
814 | return -1; |
815 | |
816 | bool ok = false; |
817 | int voltage = current.readAll().simplified().toInt(ok: &ok); |
818 | if (ok) |
819 | return voltage / 1000; |
820 | return -1; |
821 | } |
822 | |
823 | QBatteryInfo::ChargerType QBatteryInfoPrivate::getChargerType() |
824 | { |
825 | QFile charger(*AC_ONLINE_SYSFS_PATH()); |
826 | if (charger.open(flags: QIODevice::ReadOnly)) { |
827 | char online; |
828 | if (charger.read(data: &online, maxlen: 1) == 1 && online == '1') |
829 | return QBatteryInfo::WallCharger; |
830 | charger.close(); |
831 | } |
832 | |
833 | QMap<QString, QString> chargerMap; |
834 | chargerMap.insert(akey: *USB0_PRESENT_SYSFS_PATH(), avalue: *USB0_TYPE_SYSFS_PATH()); |
835 | chargerMap.insert(akey: *USB_PRESENT_SYSFS_PATH(), avalue: *USB_TYPE_SYSFS_PATH()); |
836 | |
837 | QList<QString> presentPaths = chargerMap.keys(); |
838 | foreach (const QString &presentPath, presentPaths) { |
839 | charger.setFileName(presentPath); |
840 | if (charger.open(flags: QIODevice::ReadOnly)) { |
841 | char present; |
842 | if (charger.read(data: &present, maxlen: 1) == 1 && present == '1') { |
843 | charger.close(); |
844 | |
845 | charger.setFileName(chargerMap.value(akey: presentPath)); |
846 | if (charger.open(flags: QIODevice::ReadOnly)) { |
847 | if (charger.readAll().simplified() == "USB_DCP" ) |
848 | return QBatteryInfo::WallCharger; |
849 | return QBatteryInfo::USBCharger; |
850 | } |
851 | } |
852 | charger.close(); |
853 | } |
854 | } |
855 | |
856 | return QBatteryInfo::UnknownCharger; |
857 | } |
858 | |
859 | QBatteryInfo::ChargingState QBatteryInfoPrivate::getChargingState(int battery) |
860 | { |
861 | QFile state(BATTERY_SYSFS_PATH()->arg(a: battery) + QStringLiteral("status" )); |
862 | if (!state.open(flags: QIODevice::ReadOnly)) |
863 | return QBatteryInfo::UnknownChargingState; |
864 | |
865 | QByteArray status = state.readAll().simplified(); |
866 | if (status == "Charging" ) |
867 | return QBatteryInfo::Charging; |
868 | else if (status == "Not charging" ) |
869 | return QBatteryInfo::IdleChargingState; |
870 | else if (status == "Discharging" ) |
871 | return QBatteryInfo::Discharging; |
872 | else if (status == "Full" ) |
873 | return QBatteryInfo::IdleChargingState; |
874 | |
875 | return QBatteryInfo::UnknownChargingState; |
876 | } |
877 | |
878 | QBatteryInfo::LevelStatus QBatteryInfoPrivate::getLevelStatus(int battery) |
879 | { |
880 | QFile levelStatusFile(BATTERY_SYSFS_PATH()->arg(a: battery) + QStringLiteral("capacity_level" )); |
881 | if (!levelStatusFile.open(flags: QIODevice::ReadOnly)) |
882 | return QBatteryInfo::LevelUnknown; |
883 | |
884 | QByteArray levelStatus = levelStatusFile.readAll().simplified(); |
885 | if (qstrcmp(str1: levelStatus, str2: "Critical" ) == 0) |
886 | return QBatteryInfo::LevelEmpty; |
887 | else if (qstrcmp(str1: levelStatus, str2: "Low" ) == 0) |
888 | return QBatteryInfo::LevelLow; |
889 | else if (qstrcmp(str1: levelStatus, str2: "Normal" ) == 0) |
890 | return QBatteryInfo::LevelOk; |
891 | else if (qstrcmp(str1: levelStatus, str2: "Full" ) == 0) |
892 | return QBatteryInfo::LevelFull; |
893 | |
894 | return QBatteryInfo::LevelUnknown; |
895 | } |
896 | |
897 | QT_END_NAMESPACE |
898 | |