ohmu
·
2026-10-15
1#include "fastfetch.h"
2#include "battery.h"
3#include "common/debug.h"
4#include "common/io.h"
5
6#include <private/device/power_managment.h>
7#include <sys/ioctl.h>
8#include <fcntl.h>
9#include <string.h>
10
11const char* parseBattery(int dfd, const char* battId, FFlist* results) {
12 FF_AUTO_CLOSE_FD int fd = openat(dfd, battId, O_RDWR);
13 if (fd < 0) {
14 FF_DEBUG("openat(%s) failed: %s", battId, strerror(errno));
15 return "openat() failed";
16 }
17
18 acpi_battery_info basic = {};
19 if (ioctl(fd, GET_BATTERY_INFO, &basic, sizeof(basic)) != 0) {
20 FF_DEBUG("ioctl(GET_BATTERY_INFO) failed");
21 return "ioctl(GET_BATTERY_INFO) failed";
22 }
23 acpi_extended_battery_info extended = {};
24 if (ioctl(fd, GET_EXTENDED_BATTERY_INFO, &extended, sizeof(extended)) != 0) {
25 FF_DEBUG("ioctl(GET_EXTENDED_BATTERY_INFO) failed");
26 return "ioctl(GET_EXTENDED_BATTERY_INFO) failed";
27 }
28
29 if (extended.last_full_charge == (uint32) -1) {
30 return "Skipped";
31 }
32
33 FFBatteryResult* battery = FF_LIST_ADD(FFBatteryResult, *results);
34 ffStrbufInitS(&battery->modelName, extended.model_number);
35 ffStrbufInitS(&battery->manufacturer, extended.oem_info);
36 ffStrbufInit(&battery->manufactureDate);
37 ffStrbufInitS(&battery->technology, extended.type); // extended.technology?
38 ffStrbufInitS(&battery->serial, extended.serial_number);
39 battery->status = FF_BATTERY_STATUS_NONE;
40 battery->temperature = FF_BATTERY_TEMP_UNSET;
41 battery->cycleCount = extended.cycles;
42 battery->timeRemaining = -1;
43 battery->capacity = (double) basic.capacity * 100. / (double) extended.last_full_charge;
44
45 if (basic.state & BATTERY_DISCHARGING) {
46 battery->status |= FF_BATTERY_STATUS_DISCHARGING;
47 }
48 if (basic.state & BATTERY_CHARGING) {
49 battery->status |= FF_BATTERY_STATUS_CHARGING;
50 }
51 if (basic.state & BATTERY_CRITICAL_STATE) {
52 battery->status |= FF_BATTERY_STATUS_CRITICAL;
53 }
54 if (basic.state & BATTERY_NOT_CHARGING || basic.state & BATTERY_CHARGING) {
55 battery->status |= FF_BATTERY_STATUS_AC_CONNECTED;
56 }
57
58 return nullptr;
59}
60
61const char* ffDetectBattery([[maybe_unused]] FFBatteryOptions* options, FFlist* results) {
62 FF_AUTO_CLOSE_DIR DIR* dir = opendir("/dev/power/acpi_battery/");
63 if (!dir) {
64 FF_DEBUG("opendir(\"/dev/power/acpi_battery/\") failed: %s", strerror(errno));
65 return "opendir(/dev/power/acpi_battery) failed";
66 }
67
68 struct dirent* entry;
69 while ((entry = readdir(dir))) {
70 if (entry->d_name[0] == '.') {
71 continue;
72 }
73 parseBattery(dirfd(dir), entry->d_name, results);
74 }
75
76 return nullptr;
77}