Merging upstream version 0.5.7.
[debian/lxpanel.git] / src / plugins / batt / batt_sys.c
1 /*
2 * batt_sys.h
3 *
4 * Copyright 2009 Juergen Hötzel <juergen@archlinux.org>
5 *
6 * Parts shameless stolen and glibified from acpi package
7 * Copyright (C) 2001 Grahame Bowland <grahame@angrygoats.net>
8 * (C) 2008-2009 Michael Meskes <meskes@debian.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 * MA 02110-1301, USA.
24 */
25
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include "batt_sys.h"
32 #include <glib/gstdio.h>
33
34 /* shrug: get rid of this */
35 #include <stdlib.h>
36 #include <string.h>
37
38 battery* battery_new() {
39 static int battery_num = 1;
40 battery * b = g_new0 ( battery, 1 );
41 battery_reset(b);
42 b->battery_num = battery_num;
43 battery_num++;
44 return b;
45 }
46
47 void battery_reset( battery * b) {
48 b->type_battery = TRUE;
49 b->capacity_unit = "mAh";
50 b->last_capacity_unit = -1;
51 b->last_capacity = -1;
52 b->voltage = -1;
53 b->design_capacity_unit = -1;
54 b->design_capacity = -1;
55 b->remaining_energy = -1;
56 b->remaining_capacity = -1;
57 b->present_rate = -1;
58 b->state = NULL;
59 }
60
61 static gchar* parse_info_file(char *filename)
62 {
63 char *buf = NULL;
64
65 if ( g_file_get_contents( filename, &buf, NULL, NULL) == TRUE )
66 {
67 gchar *value = g_strdup( buf );
68 value = g_strstrip( value );
69 g_free( buf );
70 return value;
71 }
72 return NULL;
73 }
74
75 static int get_unit_value(char *value)
76 {
77 int n = -1;
78 sscanf(value, "%d", &n);
79 return n;
80 }
81
82 void battery_print(battery *b, int show_capacity)
83 {
84 if ( b->type_battery )
85 {
86 if (b->state) {
87
88 printf("%s %d: %s, %d%%", BATTERY_DESC, b->battery_num - 1, b->state, b->percentage);
89
90
91 if (b->seconds > 0) {
92 b->hours = b->seconds / 3600;
93 b->seconds -= 3600 * b->hours;
94 b->minutes = b->seconds / 60;
95 b->seconds -= 60 * b->minutes;
96 printf(", %02d:%02d:%02d%s", b->hours, b->minutes, b->seconds, b->poststr);
97 } else if (b->poststr != NULL) {
98 printf(", %s", b->poststr);
99 }
100
101
102 printf("\n");
103
104 if (show_capacity && b->design_capacity > 0) {
105 if (b->last_capacity <= 100) {
106 /* some broken systems just give a percentage here */
107 b->percentage = b->last_capacity;
108 b->last_capacity = b->percentage * b->design_capacity / 100;
109 } else {
110 b->percentage = b->last_capacity * 100 / b->design_capacity;
111 }
112 if (b->percentage > 100)
113 b->percentage = 100;
114
115 printf ("%s %d: design capacity %d %s, last full capacity %d %s = %d%%\n",
116 BATTERY_DESC, b->battery_num - 1, b->design_capacity, b->capacity_unit, b->last_capacity, b->capacity_unit, b->percentage);
117 }
118 }
119 }
120 }
121
122
123 void battery_update( battery *b ) {
124 int i = 0;
125 const gchar *sys_list[] = {
126 "current_now",
127 "charge_now",
128 "energy_now",
129 "voltage_now",
130 "voltage_min_design",
131 "charge_full",
132 "energy_full",
133 "charge_full_design",
134 "energy_full_design",
135 "online",
136 "status",
137 "type",
138 NULL
139 };
140 const gchar *sys_file;
141
142 battery_reset(b);
143
144 while ( (sys_file = sys_list[i]) != NULL ) {
145
146 gchar *file_content;
147 GString *filename = g_string_new( ACPI_PATH_SYS_POWER_SUPPY );
148 g_string_append_printf ( filename, "/%s/%s", b->path,
149 sys_file );
150 if ((file_content = parse_info_file(filename->str)) != NULL) {
151
152 if ( strcmp("charge_now", sys_file ) == 0 ) {
153 b->remaining_capacity = get_unit_value((gchar*) file_content) / 1000;
154 if (!b->state)
155 b->state = "available";
156 }
157 else if ( strcmp("energy_now", sys_file ) == 0 ) {
158 b->remaining_energy = get_unit_value((gchar*) file_content) / 1000;
159 if (!b->state)
160 b->state = "available";
161 }
162 else if ( strcmp("current_now", sys_file ) == 0 ) {
163 b->present_rate = get_unit_value((gchar*) file_content) / 1000;
164 }
165 else if ( strcmp("charge_full", sys_file ) == 0 ) {
166 b->last_capacity = get_unit_value((gchar*) file_content) / 1000;
167 if (!b->state)
168 b->state = ("available");
169 }
170 else if ( strcmp("energy_full", sys_file ) == 0 ) {
171 b->last_capacity_unit = get_unit_value((gchar*) file_content) / 1000;
172 if (!b->state)
173 b->state = ("available");
174 }
175 else if ( strcmp("charge_full_design", sys_file ) == 0 ) {
176 b->design_capacity = get_unit_value((gchar*) file_content) / 1000;
177 }
178 else if ( strcmp("energy_full_design", sys_file ) == 0 ) {
179 b->design_capacity_unit = get_unit_value((gchar*) file_content) / 1000;
180 }
181 else if ( strcmp("type", sys_file ) == 0 ) {
182 b->type_battery = (strcasecmp(file_content, "battery") == 0 );
183 }
184 else if ( ( strcmp("status", sys_file ) == 0 ) || strcmp("state", sys_file ) == 0 )
185 b->state = file_content;
186 else if ( strcmp("voltage_now", sys_file ) == 0 ) {
187 b->voltage = get_unit_value((gchar*) file_content) / 1000;
188 }
189
190 g_string_free( filename, TRUE );
191 }
192 i++;
193 }
194
195 /* convert energy values (in mWh) to charge values (in mAh) if needed and possible */
196 if (b->last_capacity_unit != -1 && b->last_capacity == -1) {
197 if (b->voltage != -1) {
198 b->last_capacity = b->last_capacity_unit * 1000 / b->voltage;
199 } else {
200 b->last_capacity = b->last_capacity_unit;
201 b->capacity_unit = "mWh";
202 }
203 }
204 if (b->design_capacity_unit != -1 && b->design_capacity == -1) {
205 if (b->voltage != -1) {
206 b->design_capacity = b->design_capacity_unit * 1000 / b->voltage;
207 } else {
208 b->design_capacity = b->design_capacity_unit;
209 b->capacity_unit = "mWh";
210 }
211 }
212 if (b->remaining_energy != -1 && b->remaining_capacity == -1) {
213 if (b->voltage != -1) {
214 b->remaining_capacity = b->remaining_energy * 1000 / b->voltage;
215 b->present_rate = b->present_rate * 1000 / b->voltage;
216 } else {
217 b->remaining_capacity = b->remaining_energy;
218 }
219 }
220 if (b->last_capacity < MIN_CAPACITY)
221 b->percentage = 0;
222 else
223 b->percentage = ((float) b->remaining_energy * 100.0) / (float) b->last_capacity_unit;
224
225 if (b->percentage > 100)
226 b->percentage = 100;
227
228
229
230 if (b->present_rate == -1) {
231 b->poststr = "rate information unavailable";
232 b->seconds = -1;
233 } else if (!strcasecmp(b->state, "charging")) {
234 if (b->present_rate > MIN_PRESENT_RATE) {
235 b->seconds = 3600 * (b->last_capacity - b->remaining_capacity) / b->present_rate;
236 b->poststr = " until charged";
237 } else {
238 b->poststr = "charging at zero rate - will never fully charge.";
239 b->seconds = -1;
240 }
241 } else if (!strcasecmp(b->state, "discharging")) {
242 if (b->present_rate > MIN_PRESENT_RATE) {
243 b->seconds = 3600 * b->remaining_capacity / b->present_rate;
244 b->poststr = " remaining";
245 } else {
246 b->poststr = "discharging at zero rate - will never fully discharge.";
247 b->seconds = -1;
248 }
249 } else {
250 b->poststr = NULL;
251 b->seconds = -1;
252 }
253
254 }
255
256 static battery* acpi_sys_get_battery_from_dir (const gchar *device_name ) {
257 battery *b = battery_new();
258 b->path = g_strdup( device_name );
259 return b;
260 }
261
262 battery *battery_get() {
263 GError * error = NULL;
264 const gchar *entry;
265 GDir * dir = g_dir_open( ACPI_PATH_SYS_POWER_SUPPY, 0, &error );
266 battery *b = NULL;
267 if ( dir == NULL )
268 {
269 g_warning( "NO ACPI/sysfs support in kernel: %s", error->message );
270 return NULL;
271 }
272 while ( ( entry = g_dir_read_name (dir) ) != NULL )
273 {
274 b = acpi_sys_get_battery_from_dir(entry);
275 battery_update ( b );
276 if ( b->type_battery == TRUE )
277 break;
278 /* ignore non-batteries */
279 else {
280 g_free(b);
281 b = NULL;
282 }
283 }
284 g_dir_close( dir );
285 return b;
286 }
287
288 gboolean battery_is_charging( battery *b )
289 {
290 return ( strcasecmp( b->state, "Unknown" ) == 0 ||
291 strcasecmp( b->state, "Full" ) == 0
292 || strcasecmp( b->state, "Charging" ) == 0 );
293 }
294
295 gint battery_get_remaining( battery *b )
296 {
297 return b->seconds;
298 }
299
300