diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/battery/battery_apple.c | |
Add the files
Diffstat (limited to 'src/detection/battery/battery_apple.c')
| -rw-r--r-- | src/detection/battery/battery_apple.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c new file mode 100644 index 0000000..c22aa6d --- /dev/null +++ b/src/detection/battery/battery_apple.c @@ -0,0 +1,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; +} |