1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#include "fastfetch.h"
#include "battery.h"
#include "common/apple/cf_helpers.h"
#include "common/apple/smc_temps.h"
#include <IOKit/IOKitLib.h>
#include <IOKit/pwr_mgt/IOPM.h>
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) {
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) {
return "IOServiceGetMatchingServices() failed";
}
io_registry_entry_t registryEntry;
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryBattery = registryEntry;
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL;
if (IORegistryEntryCreateCFProperties(entryBattery, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) {
continue;
}
int currentCapacity, maxCapacity;
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0) {
continue;
}
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity) != NULL || currentCapacity <= 0) {
continue;
}
bool boolValue;
FFBatteryResult* battery = FF_LIST_ADD(FFBatteryResult, *results);
battery->temperature = FF_BATTERY_TEMP_UNSET;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->serial);
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->manufactureDate);
battery->status = FF_BATTERY_STATUS_NONE;
battery->capacity = currentCapacity * 100.0 / maxCapacity;
battery->cycleCount = 0;
battery->timeRemaining = -1;
ffCfDictGetString(properties, CFSTR(kIOPMDeviceNameKey), &battery->modelName);
ffCfDictGetString(properties, CFSTR(kIOPMPSSerialKey), &battery->serial);
ffCfDictGetString(properties, CFSTR(kIOPMPSManufacturerKey), &battery->manufacturer);
if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue) {
if (!battery->manufacturer.length) {
ffStrbufAppendS(&battery->manufacturer, "Apple Inc.");
}
ffStrbufAppendS(&battery->technology, "Lithium");
if (!battery->modelName.length) {
ffStrbufAppendS(&battery->modelName, "Built-in");
}
}
int32_t cycleCount = 0;
ffCfDictGetInt(properties, CFSTR(kIOPMPSCycleCountKey), &cycleCount);
battery->cycleCount = cycleCount < 0 ? 0 : (uint32_t) cycleCount;
battery->timeRemaining = -1;
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSExternalConnectedKey), &boolValue) == NULL) {
if (boolValue) {
battery->status |= FF_BATTERY_STATUS_AC_CONNECTED;
} else {
battery->status |= FF_BATTERY_STATUS_DISCHARGING;
ffCfDictGetInt(properties, CFSTR("AvgTimeToEmpty"), &battery->timeRemaining); // in minutes
if (battery->timeRemaining < 0 || battery->timeRemaining >= 0xFFFF) {
battery->timeRemaining = -1;
} else {
battery->timeRemaining *= 60;
}
}
}
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSIsChargingKey), &boolValue) == NULL && boolValue) {
battery->status |= FF_BATTERY_STATUS_CHARGING;
}
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSAtCriticalLevelKey), &boolValue) == NULL && boolValue) {
battery->status |= FF_BATTERY_STATUS_CRITICAL;
}
int sbdsManufactureDate = 0;
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSManufactureDateKey), &sbdsManufactureDate) == NULL) {
int day = sbdsManufactureDate & 0b11111;
int month = (sbdsManufactureDate >> 5) & 0b1111;
int year = (sbdsManufactureDate >> 9) + 1800;
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
} else {
CFDictionaryRef batteryData;
if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL) {
char manufactureDate[sizeof(uint64_t)];
if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL) {
// https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419
int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8;
int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0');
int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '0');
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
}
}
}
if (options->temp) {
int64_t temp;
if (!ffCfDictGetInt64(properties, CFSTR(kIOPMPSBatteryTemperatureKey), &temp)) {
battery->temperature = (double) temp / 10 - 273.15;
} else {
ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature);
}
}
}
return NULL;
}
|