wmpager: EWMH support
[dockapps.git] / wmacpi / libacpi.c
blob120a157df4d2ff939f92fe9eeaaf7a7e46abfb6a
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <dirent.h>
7 #include "wmacpi.h"
9 #define MAXBATT 8
11 #ifdef ACPI
12 #ifdef PRO
13 extern char *state[];
14 #endif
15 extern APMInfo *apminfo;
16 static char batteries[MAXBATT][128];
17 static char battinfo[MAXBATT][128];
18 int batt_count;
19 /* temp buffer */
20 char buf[512];
22 /* local proto */
23 int acpi_get_design_cap(int battery);
25 /* see if we have ACPI support and check version */
26 int power_init(void)
28 FILE *acpi;
29 char buf[4096];
30 DIR *battdir;
31 struct dirent *batt;
32 char *name;
33 int acpi_ver = 0;
35 if (!(acpi = fopen("/proc/acpi/info", "r"))) {
36 fprintf(stderr, "This system does not support ACPI\n");
37 return 1;
40 /* okay, now see if we got the right version */
41 fread(buf, 4096, 1, acpi);
42 acpi_ver = strtol(buf + 25, NULL, 10);
43 eprint(1, "ACPI version detected: %d\n", acpi_ver);
44 if (acpi_ver < 20020214) {
45 fprintf(stderr, "This version requires ACPI subsystem version 20020214\n");
46 fclose(acpi);
47 return 1;
50 /* yep, all good */
51 fclose(acpi);
53 /* now enumerate batteries */
54 batt_count = 0;
55 battdir = opendir("/proc/acpi/battery");
56 if (battdir == NULL) {
57 fprintf(stderr, "No batteries or ACPI not supported\n");
58 return 1;
60 while ((batt = readdir(battdir))) {
61 name = batt->d_name;
63 /* skip . and .. */
64 if (!strncmp(".", name, 1) || !strncmp("..", name, 2))
65 continue;
67 sprintf(batteries[batt_count], "/proc/acpi/battery/%s/state", name);
68 sprintf(battinfo[batt_count], "/proc/acpi/battery/%s/info", name);
69 eprint(1, "battery detected at %s\n", batteries[batt_count]);
70 batt_count++;
72 closedir(battdir);
74 /* tell user some info */
75 eprint(1, "%d batteries detected\n", batt_count);
76 fprintf(stderr, "wmacpi: found %d batter%s\n", batt_count,
77 (batt_count == 1) ? "y" : "ies");
79 return 0;
82 int acpi_get_design_cap(int battery)
84 FILE *acpi;
85 char *ptr;
86 int design_cap;
88 if (battery > MAXBATT)
89 return -1;
91 if (!(acpi = fopen(battinfo[battery], "r")))
92 return -1;
94 fread(buf, 512, 1, acpi);
95 fclose(acpi);
97 if ((ptr = strstr(buf, "last full capacity"))) {
98 ptr += 25;
99 sscanf(ptr, "%d", &design_cap);
100 eprint(1, "last full capacity: %d\n", design_cap);
101 } else {
102 /* hack. if there isnt any info on last capacity, we are
103 * screwed, but let's not come back here again */
104 design_cap = -1;
105 eprint(1, "Cannot retrieve design capacity!");
108 return design_cap;
111 void acquire_info(void)
113 FILE *acpi;
114 char *ptr;
115 char stat;
117 static int dcap = 0xdeadbeef;
119 int percent = 100; /* battery percentage */
120 int ptemp, rate, rtime = 0;
122 if (dcap == 0xdeadbeef) {
123 /* get from first battery for now */
124 dcap = acpi_get_design_cap(0);
127 if (!(acpi = fopen(batteries[0], "r")))
128 return;
130 eprint(1, "opened acpi file successfully");
131 fread(buf, 512, 1, acpi);
132 fclose(acpi);
134 /* This section of the code will calculate "percentage remaining"
135 * using battery capacity, and the following formula (acpi spec 3.9.2):
136 * percentage = (current_capacity / last_full_capacity) * 100; */
137 if ((ptr = strstr(buf, "remaining capacity"))) {
138 ptr += 25;
139 sscanf(ptr, "%d", &ptemp);
140 eprint(1, "capacity: %d\n", ptemp);
141 percent = (float)((float)ptemp / (float)dcap) * 100;
142 eprint(1, "percent: %d\n", percent);
144 apminfo->percentage = percent;
146 /* this section of code will calculate "time remaining"
147 * using battery remaining capacity, and battery "rate" (3.9.3) */
148 if ((ptr = strstr(buf, "present rate"))) {
149 ptr += 25;
150 sscanf(ptr, "%d", &rate);
151 eprint(1, "rate: %d\n", rate);
152 if (rate <= 0)
153 rate = 0;
154 /* time remaining in minutes */
155 rtime = ((float)((float)ptemp / (float)rate)) * 60;
156 if (rtime <= 0)
157 rtime = 0;
158 eprint(1, "time rem: %d\n", rtime);
160 apminfo->rtime = rtime;
162 if ((ptr = strstr(buf, "charging state"))) {
163 /* found battery discharging. This is used to determine if
164 * we are on AC power or not. Notice check for "ch" later on */
165 stat = *(ptr + 25);
166 if (stat == 'o' || stat == 'u') /* "ok" | "unknown" : charged, on ac power */
167 apminfo->power = POWER;
168 else
169 /* we set this, and later on use percentage
170 * value to determine high/med/low */
171 apminfo->power = HIGH;
173 /* but if we are on power, we might be charging too. Check. */
174 if ((ptr = strstr(buf, "charging state"))) {
175 /* found battery charging line. We will change power state
176 * if we are on power, and charging. */
177 stat = *(ptr + 25);
178 /* this is seriously stupid - but we catch "critical" */
179 if (stat == 'c' && (*(ptr + 26) == 'h'))
180 apminfo->power = CHARGING;
184 /* we are not on power, and not charging. So, it would make sense
185 * to check if battery is "critical low", and calculate interesting
186 * things like battery HIGH/LOW, and maybe battery usage LOAD
187 * This will be replaced with some code to allow setting user-specified
188 * low / critical alarms */
189 if ((apminfo->power != POWER) && (apminfo->power != CHARGING)) {
190 eprint(1, "entering battery status check");
191 if ((ptr = strstr(buf, "capacity state"))) {
192 stat = *(ptr + 25);
193 /* only check "c" here because we already caught "CHarging" earlier
194 * and also look into crit_level */
195 if (stat == 'c' || (apminfo->percentage <= apminfo->crit_level)) {
196 /* nothing else to do here - critical battery. get out */
197 eprint(1, "Received critical battery status");
198 apminfo->power = CRIT;
202 process_plugin_timer();
204 eprint(1, "current state: %s (%d)", state[apminfo->power], apminfo->power);
206 #endif /* ACPI */