Refactor battery information handling for old and new devices

This commit is contained in:
uncor3
2025-09-27 11:31:25 +00:00
parent 43aa783433
commit 3b9df7577b
4 changed files with 141 additions and 88 deletions
+1 -9
View File
@@ -17,16 +17,8 @@ void get_battery_info(std::string productType, idevice_t idevice,
return;
}
bool newerThaniPhone8 =
is_product_type_newer(productType, std::string("iPhone8,1"));
const char *batteryQuery =
is_iphone
? newerThaniPhone8 ? "AppleSmartBattery" : "AppleARMPMUCharger"
: "AppleARMPMUCharger";
if (diagnostics_relay_query_ioregistry_entry(
diagnostics_client, nullptr, batteryQuery, &diagnostics) !=
diagnostics_client, nullptr, "IOPMPowerSource", &diagnostics) !=
DIAGNOSTICS_RELAY_E_SUCCESS &&
!diagnostics) {
+127 -47
View File
@@ -34,6 +34,87 @@ std::string safeGetXML(const char *key, pugi::xml_node dict)
return "";
}
// this is reused in the ui in deviceinfowidget
void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d)
{
d.batteryInfo.isCharging = ioreg["IsCharging"].getBool();
d.batteryInfo.fullyCharged = ioreg["FullyCharged"].getBool();
uint64_t appleRawCurrentCapacity =
ioreg["AppleRawCurrentCapacity"].getUInt();
uint64_t appleRawMaxCapacity = ioreg["AppleRawMaxCapacity"].getUInt();
qDebug() << "appleRawCurrentCapacity" << appleRawCurrentCapacity;
qDebug() << "appleRawMaxCapacity" << appleRawMaxCapacity;
uint64_t oldCurrrentBatteryLevel =
(appleRawCurrentCapacity && appleRawMaxCapacity)
? (appleRawCurrentCapacity * 100 / appleRawMaxCapacity)
: 0;
qDebug() << "oldCurrrentBatteryLevel" << oldCurrrentBatteryLevel;
d.batteryInfo.currentBatteryLevel = oldCurrrentBatteryLevel;
// adaptor details
d.batteryInfo.usbConnectionType =
ioreg["AdapterDetails"]["Description"].getString() == "usb type-c"
? BatteryInfo::ConnectionType::USB_TYPEC
: BatteryInfo::ConnectionType::USB;
d.batteryInfo.adapterVoltage = 0;
// watt
d.batteryInfo.watts = ioreg["AdapterDetails"]["Watts"].getUInt();
}
void parseOldDevice(PlistNavigator &ioreg, DeviceInfo &d)
{
uint64_t cycleCount = ioreg["CycleCount"].getUInt();
// skipping on very old devices for now
std::string batterySerialNumber = "";
uint64_t designCapacity = ioreg["DesignCapacity"].getUInt();
uint64_t maxCapacity = ioreg["MaxCapacity"].getUInt();
qDebug() << "Design capacity: " << designCapacity;
qDebug() << "Max capacity: " << maxCapacity;
// Compat
int healthPercent =
(designCapacity != 0) ? (maxCapacity * 100) / designCapacity : 0;
healthPercent = std::min(healthPercent, 100);
d.batteryInfo.health = QString::number(healthPercent) + "%";
d.batteryInfo.cycleCount = cycleCount;
d.batteryInfo.serialNumber = !batterySerialNumber.empty()
? batterySerialNumber
: "Error retrieving serial number";
parseOldDeviceBattery(ioreg, d);
}
// this is reused in the ui in deviceinfowidget
void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d)
{
d.batteryInfo.isCharging = ioreg["IsCharging"].getBool();
d.batteryInfo.fullyCharged = ioreg["FullyCharged"].getBool();
d.batteryInfo.currentBatteryLevel =
ioreg["BatteryData"]["StateOfCharge"].getUInt();
d.batteryInfo.usbConnectionType =
ioreg["AdapterDetails"]["Description"].getString() == "usb type-c"
? BatteryInfo::ConnectionType::USB_TYPEC
: BatteryInfo::ConnectionType::USB;
// adaptor details
d.batteryInfo.adapterVoltage =
ioreg["AppleRawAdapterDetails"][0]["AdapterVoltage"].getUInt();
d.batteryInfo.watts = ioreg["AppleRawAdapterDetails"][0]["Watts"].getUInt();
}
// TODO: return tyype
DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
afc_client_t &afcClient,
@@ -106,6 +187,10 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
d.productionDevice = safeGetBool("ProductionSOC");
if (_activationState == "Activated") {
d.activationState = DeviceInfo::ActivationState::Activated;
// IOS 6
} else if (_activationState == "WildcardActivated") {
d.activationState =
DeviceInfo::ActivationState::Activated; // Treat as activated
} else if (_activationState == "FactoryActivated") {
d.activationState = DeviceInfo::ActivationState::FactoryActivated;
} else if (_activationState == "Unactivated") {
@@ -124,66 +209,61 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
/*BatteryInfo*/
plist_t diagnostics = nullptr;
get_battery_info(rawProductType, result.device, d.is_iPhone, diagnostics);
plist_print(diagnostics);
if (!diagnostics) {
qDebug() << "Failed to get diagnostics plist.";
return d;
}
try {
PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"];
plist_print(diagnostics);
uint64_t cycleCount =
PlistNavigator(diagnostics)["IORegistry"]["BatteryData"]["CycleCount"]
.getUInt();
// old devices do not have "BatteryData"
d.oldDevice = !ioreg["BatteryData"];
if (d.oldDevice) {
parseOldDevice(ioreg, d);
plist_free(diagnostics);
diagnostics = nullptr;
return d;
}
std::string batterySerialNumber =
PlistNavigator(
diagnostics)["IORegistry"]["BatteryData"]["BatterySerialNumber"]
.getString();
uint64_t designCapacity =
PlistNavigator(
diagnostics)["IORegistry"]["BatteryData"]["DesignCapacity"]
.getUInt();
bool newerThaniPhone8 =
is_product_type_newer(rawProductType, std::string("iPhone8,1"));
uint64_t appleRawCurrentCapacity =
PlistNavigator(diagnostics)["IORegistry"]["AppleRawCurrentCapacity"]
.getUInt();
uint64_t cycleCount = ioreg["BatteryData"]["CycleCount"].getUInt();
d.batteryInfo.health =
QString::number((appleRawCurrentCapacity * 100) / designCapacity) + "%";
d.batteryInfo.cycleCount = cycleCount;
d.batteryInfo.serialNumber = !batterySerialNumber.empty()
? batterySerialNumber
: "Error retrieving serial number";
// Battery serial number
std::string batterySerialNumber =
ioreg["BatteryData"]["BatterySerialNumber"].getString();
d.batteryInfo.isCharging =
PlistNavigator(diagnostics)["IORegistry"]["IsCharging"].getBool();
uint64_t designCapacity =
ioreg["BatteryData"]["DesignCapacity"].getUInt();
d.batteryInfo.fullyCharged =
PlistNavigator(diagnostics)["IORegistry"]["FullyCharged"].getBool();
uint64_t maxCapacity =
d.is_iPhone ? newerThaniPhone8
? ioreg["AppleRawMaxCapacity"].getUInt()
: ioreg["BatteryData"]["MaxCapacity"].getUInt()
: ioreg["BatteryData"]["MaxCapacity"].getUInt();
d.batteryInfo.currentBatteryLevel =
PlistNavigator(diagnostics)["IORegistry"]["CurrentCapacity"].getUInt();
qDebug() << "Design capacity: " << designCapacity;
qDebug() << "Max capacity: " << maxCapacity;
d.batteryInfo.usbConnectionType =
PlistNavigator(
diagnostics)["IORegistry"]["AdapterDetails"]["Description"]
.getString() == "usb type-c"
? BatteryInfo::ConnectionType::USB_TYPEC
: BatteryInfo::ConnectionType::USB;
// seems to be to the most accurate way to get health
d.batteryInfo.health =
QString::number((maxCapacity * 100) / designCapacity) + "%";
d.batteryInfo.cycleCount = cycleCount;
d.batteryInfo.serialNumber = !batterySerialNumber.empty()
? batterySerialNumber
: "Error retrieving serial number";
parseDeviceBattery(ioreg, d);
plist_free(diagnostics);
diagnostics = nullptr;
d.batteryInfo.adapterVoltage =
PlistNavigator(diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]
["AdapterVoltage"]
.getUInt();
d.batteryInfo.watts =
PlistNavigator(
diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]["Watts"]
.getUInt();
plist_free(diagnostics);
diagnostics = nullptr;
return d;
return d;
} catch (const std::exception &e) {
qDebug() << "Error occurred: " << e.what();
return d;
}
}
// TODO: need to handle errors and free resources properly
+6 -28
View File
@@ -322,35 +322,13 @@ void DeviceInfoWidget::updateBatteryInfo()
}
/*DATA*/
DeviceInfo &d = m_device->deviceInfo;
d.batteryInfo.isCharging =
PlistNavigator(diagnostics)["IORegistry"]["IsCharging"].getBool();
d.batteryInfo.fullyCharged =
PlistNavigator(diagnostics)["IORegistry"]["FullyCharged"].getBool();
d.batteryInfo.currentBatteryLevel =
PlistNavigator(diagnostics)["IORegistry"]["CurrentCapacity"].getUInt();
d.batteryInfo.usbConnectionType =
PlistNavigator(
diagnostics)["IORegistry"]["AdapterDetails"]["Description"]
.getString() == "usb type-c"
? BatteryInfo::ConnectionType::USB_TYPEC
: BatteryInfo::ConnectionType::USB;
d.batteryInfo.adapterVoltage =
PlistNavigator(diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]
["AdapterVoltage"]
.getUInt();
d.batteryInfo.watts =
PlistNavigator(
diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]["Watts"]
.getUInt();
qDebug() << "old device" << d.oldDevice;
PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"];
if (d.oldDevice)
parseOldDeviceBattery(ioreg, d);
else
parseDeviceBattery(ioreg, d);
/*UI*/
m_chargingStatusLabel->setText(d.batteryInfo.isCharging ? "Charging"
: "Not Charging");
m_chargingWattsLabel->setText(QString::number(d.batteryInfo.watts) + "W");
+7 -4
View File
@@ -131,6 +131,7 @@ struct DeviceInfo {
BatteryInfo batteryInfo;
DiskInfo diskInfo;
bool is_iPhone;
bool oldDevice;
};
struct iDescriptorDevice {
@@ -260,7 +261,7 @@ private:
public:
PlistNavigator(plist_t node) : current_node(node) {}
// Existing dictionary key access
// dict key access
PlistNavigator operator[](const char *key)
{
if (!current_node || plist_get_node_type(current_node) != PLIST_DICT) {
@@ -270,7 +271,7 @@ public:
return PlistNavigator(next);
}
// Add array index access
// array index access
PlistNavigator operator[](int index)
{
if (!current_node || plist_get_node_type(current_node) != PLIST_ARRAY) {
@@ -287,7 +288,6 @@ public:
operator plist_t() const { return current_node; }
bool valid() const { return current_node != nullptr; }
// Your existing helper methods
bool getBool() const
{
if (!current_node)
@@ -437,4 +437,7 @@ bool query_mobile_gestalt(iDescriptorDevice *id_device, const QStringList &keys,
std::string safeGetXML(const char *key, pugi::xml_node dict);
void get_battery_info(std::string productType, idevice_t idevice,
bool is_iphone, plist_t &diagnostics);
bool is_iphone, plist_t &diagnostics);
void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d);
void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d);