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