ohmu
·
2026-10-15
1#include "battery.h"
2#include "common/debug.h"
3#include "common/io.h"
4
5#include <string.h>
6#include <machine/apmvar.h>
7#include <sys/ioctl.h>
8#include <unistd.h>
9#include <fcntl.h>
10
11const char* ffDetectBattery([[maybe_unused]] FFBatteryOptions* options, FFlist* result) {
12 FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY | O_CLOEXEC);
13
14 if (devfd < 0) {
15 FF_DEBUG("open(\"/dev/apm\") failed: %s", strerror(errno));
16 return "open(dev/apm, O_RDONLY | O_CLOEXEC) failed";
17 }
18
19 struct apm_power_info info = {};
20
21 if (ioctl(devfd, APM_IOC_GETPOWER, &info) < 0) {
22 FF_DEBUG("ioctl(APM_IOC_GETPOWER) failed: %s", strerror(errno));
23 return "ioctl(APM_IOC_GETPOWER) failed";
24 }
25
26 if (info.battery_state == APM_BATTERY_ABSENT) {
27 return nullptr;
28 }
29
30 FFBatteryResult* battery = FF_LIST_ADD(FFBatteryResult, *result);
31 battery->temperature = FF_BATTERY_TEMP_UNSET;
32 battery->cycleCount = 0;
33 battery->timeRemaining = -1;
34 battery->capacity = info.battery_life;
35 ffStrbufInit(&battery->manufacturer);
36 ffStrbufInit(&battery->modelName);
37 ffStrbufInit(&battery->technology);
38 ffStrbufInit(&battery->serial);
39 ffStrbufInit(&battery->manufactureDate);
40 battery->status = FF_BATTERY_STATUS_NONE;
41
42 if (info.ac_state == APM_AC_ON || info.ac_state == APM_AC_BACKUP) {
43 battery->status |= FF_BATTERY_STATUS_AC_CONNECTED;
44 } else if (info.ac_state == APM_AC_OFF) {
45 battery->timeRemaining = (int) info.minutes_left * 60;
46 battery->status |= FF_BATTERY_STATUS_DISCHARGING;
47 }
48
49 if (info.battery_state == APM_BATT_CRITICAL || info.battery_state == APM_BATT_CHARGING || info.battery_state == APM_BATT_UNKNOWN) {
50 switch (info.battery_state) {
51 case APM_BATT_UNKNOWN:
52 battery->status |= FF_BATTERY_STATUS_UNKNOWN;
53 break;
54 case APM_BATT_CHARGING:
55 battery->status |= FF_BATTERY_STATUS_CHARGING;
56 break;
57 case APM_BATT_CRITICAL:
58 battery->status |= FF_BATTERY_STATUS_CRITICAL;
59 break;
60 }
61 }
62
63 return nullptr;
64}