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
47QT_BEGIN_NAMESPACE
48
49Q_GLOBAL_STATIC_WITH_ARGS(const QString, AC_ONLINE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/AC/online")))
50Q_GLOBAL_STATIC_WITH_ARGS(const QString, BATTERY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/BAT%1/")))
51Q_GLOBAL_STATIC_WITH_ARGS(const QString, POWER_SUPPLY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/")))
52Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB_PRESENT_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/usb/present")))
53Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB_TYPE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/usb/type")))
54Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB0_PRESENT_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/USB0/present")))
55Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB0_TYPE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/USB0/type")))
56
57QBatteryInfoPrivate::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
81QBatteryInfoPrivate::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
105QBatteryInfoPrivate::~QBatteryInfoPrivate()
106{
107#if defined(QT_NO_UDEV)
108 delete timer;
109#endif // QT_NO_UDEV
110}
111
112int QBatteryInfoPrivate::batteryCount()
113{
114 if (!watchBatteryCount)
115 return getBatteryCount();
116
117 return batteryCounts;
118}
119
120int QBatteryInfoPrivate::batteryIndex() const
121{
122 return index;
123}
124
125bool QBatteryInfoPrivate::isValid()
126{
127 // valid if the index < total count.
128 return (index >= 0) && (index < batteryCount());
129}
130
131void 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
210int 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
221int QBatteryInfoPrivate::level()
222{
223 return level(battery: index);
224}
225
226int QBatteryInfoPrivate::currentFlow(int battery)
227{
228 if (!watchCurrentFlow)
229 return getCurrentFlow(battery);
230
231 return currentFlows.value(akey: battery);
232}
233
234int QBatteryInfoPrivate::currentFlow()
235{
236 return currentFlow(battery: index);
237}
238
239int QBatteryInfoPrivate::cycleCount(int battery)
240{
241 Q_UNUSED(battery)
242
243 return -1;
244}
245
246int QBatteryInfoPrivate::cycleCount()
247{
248 return cycleCount(battery: index);
249}
250
251int 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
270int QBatteryInfoPrivate::maximumCapacity()
271{
272 return maximumCapacity(battery: index);
273}
274
275int QBatteryInfoPrivate::remainingCapacity(int battery)
276{
277 if (!watchRemainingCapacity)
278 return getRemainingCapacity(battery);
279
280 return remainingCapacities.value(akey: battery);
281}
282
283int QBatteryInfoPrivate::remainingCapacity()
284{
285 return remainingCapacity(battery: index);
286}
287
288int QBatteryInfoPrivate::remainingChargingTime(int battery)
289{
290 if (!watchRemainingChargingTime)
291 return getRemainingChargingTime(battery);
292
293 return remainingChargingTimes.value(akey: battery);
294}
295
296int QBatteryInfoPrivate::remainingChargingTime()
297{
298 return remainingChargingTime(battery: index);
299}
300
301int QBatteryInfoPrivate::voltage(int battery)
302{
303 if (!watchVoltage)
304 return getVoltage(battery);
305
306 return voltages.value(akey: battery);
307}
308
309int QBatteryInfoPrivate::voltage()
310{
311 return voltage(battery: index);
312}
313
314QBatteryInfo::ChargerType QBatteryInfoPrivate::chargerType()
315{
316 if (!watchChargerType)
317 return getChargerType();
318
319 return currentChargerType;
320}
321
322QBatteryInfo::ChargingState QBatteryInfoPrivate::chargingState(int battery)
323{
324 if (!watchChargingState)
325 return getChargingState(battery);
326
327 return chargingStates.value(akey: battery);
328}
329
330QBatteryInfo::ChargingState QBatteryInfoPrivate::chargingState()
331{
332 return chargingState(battery: index);
333}
334
335QBatteryInfo::LevelStatus QBatteryInfoPrivate::levelStatus(int battery)
336{
337 if (!watchLevelStatus)
338 return getLevelStatus(battery);
339
340 return levelStatuss.value(akey: battery);
341}
342
343QBatteryInfo::LevelStatus QBatteryInfoPrivate::levelStatus()
344{
345 return levelStatus(battery: index);
346}
347
348QBatteryInfo::Health QBatteryInfoPrivate::health(int battery)
349{
350 Q_UNUSED(battery)
351
352 return QBatteryInfo::HealthUnknown;
353}
354
355QBatteryInfo::Health QBatteryInfoPrivate::health()
356{
357 return health(battery: index);
358}
359
360float QBatteryInfoPrivate::temperature(int battery)
361{
362 Q_UNUSED(battery)
363
364 return qQNaN();
365}
366
367float QBatteryInfoPrivate::temperature()
368{
369 return temperature(battery: index);
370}
371
372void 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
453void 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
528void 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
629void 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
650void 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
738int QBatteryInfoPrivate::getBatteryCount()
739{
740 return QDir(*POWER_SUPPLY_SYSFS_PATH()).entryList(nameFilters: QStringList() << QStringLiteral("BAT*")).size();
741}
742
743int 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
769int 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
782int 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
810int 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
823QBatteryInfo::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
859QBatteryInfo::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
878QBatteryInfo::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
897QT_END_NAMESPACE
898

source code of qtsystems/src/systeminfo/linux/qbatteryinfo_linux.cpp