Merging upstream version 0.5.3.
[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 b->type_battery = TRUE;
42 b->capacity_unit = "mAh";
43 b->last_capacity_unit = -1;
44 b->last_capacity = -1;
45 b->voltage = -1;
46 b->design_capacity_unit = -1;
47 b->design_capacity = -1;
48 b->remaining_energy = -1;
49 b->remaining_capacity = -1;
50 b->present_rate = -1;
51 b->state = NULL;
52 b->battery_num = battery_num;
53 battery_num++;
54 return b;
55 }
56
57
58 static gchar* parse_info_file(char *filename)
59 {
60 char *buf = NULL;
61
62 if ( g_file_get_contents( filename, &buf, NULL, NULL) == TRUE )
63 {
64 gchar *value = g_strdup( buf );
65 value = g_strstrip( value );
66 g_free( buf );
67 return value;
68 }
69 return NULL;
70 }
71
72 static int get_unit_value(char *value)
73 {
74 int n = -1;
75 sscanf(value, "%d", &n);
76 return n;
77 }
78
79 void battery_print(battery *b, int show_capacity)
80 {
81 if ( b->type_battery )
82 {
83 if (b->state) {
84
85 printf("%s %d: %s, %d%%", BATTERY_DESC, b->battery_num - 1, b->state, b->percentage);
86
87
88 if (b->seconds > 0) {
89 b->hours = b->seconds / 3600;
90 b->seconds -= 3600 * b->hours;
91 b->minutes = b->seconds / 60;
92 b->seconds -= 60 * b->minutes;
93 printf(", %02d:%02d:%02d%s", b->hours, b->minutes, b->seconds, b->poststr);
94 } else if (b->poststr != NULL) {
95 printf(", %s", b->poststr);
96 }
97
98
99 printf("\n");
100
101 if (show_capacity && b->design_capacity > 0) {
102 if (b->last_capacity <= 100) {
103 /* some broken systems just give a percentage here */
104 b->percentage = b->last_capacity;
105 b->last_capacity = b->percentage * b->design_capacity / 100;
106 } else {
107 b->percentage = b->last_capacity * 100 / b->design_capacity;
108 }
109 if (b->percentage > 100)
110 b->percentage = 100;
111
112 printf ("%s %d: design capacity %d %s, last full capacity %d %s = %d%%\n",
113 BATTERY_DESC, b->battery_num - 1, b->design_capacity, b->capacity_unit, b->last_capacity, b->capacity_unit, b->percentage);
114 }
115 }
116 }
117 }
118
119
120 void battery_update( battery *b ) {
121 int i = 0;
122 const gchar *sys_list[] = {
123 "current_now",
124 "charge_now",
125 "energy_now",
126 "voltage_now",
127 "voltage_min_design",
128 "charge_full",
129 "energy_full",
130 "charge_full_design",
131 "energy_full_design",
132 "online",
133 "status",
134 "type",
135 NULL
136 };
137 const gchar *sys_file;
138
139 while ( (sys_file = sys_list[i]) != NULL ) {
140
141 gchar *file_content;
142 GString *filename = g_string_new( ACPI_PATH_SYS_POWER_SUPPY );
143 g_string_append_printf ( filename, "/%s/%s", b->path,
144 sys_file );
145 if ((file_content = parse_info_file(filename->str)) != NULL) {
146
147 if ( strcmp("charge_now", sys_file ) == 0 ) {
148 b->remaining_capacity = get_unit_value((gchar*) file_content) / 1000;
149 if (!b->state)
150 b->state = "available";
151 }
152 else if ( strcmp("energy_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("current_now", sys_file ) == 0 ) {
158 b->present_rate = get_unit_value((gchar*) file_content) / 1000;
159 }
160 else if ( strcmp("charge_full", sys_file ) == 0 ) {
161 b->last_capacity = get_unit_value((gchar*) file_content) / 1000;
162 if (!b->state)
163 b->state = ("available");
164 }
165 else if ( strcmp("energy_full", sys_file ) == 0 ) {
166 b->last_capacity_unit = get_unit_value((gchar*) file_content) / 1000;
167 if (!b->state)
168 b->state = ("available");
169 }
170 else if ( strcmp("charge_full_design", sys_file ) == 0 ) {
171 b->design_capacity = get_unit_value((gchar*) file_content) / 1000;
172 }
173 else if ( strcmp("energy_full_design", sys_file ) == 0 ) {
174 b->design_capacity_unit = get_unit_value((gchar*) file_content) / 1000;
175 }
176 else if ( strcmp("type", sys_file ) == 0 ) {
177 b->type_battery = (strcasecmp(file_content, "battery") == 0 );
178 }
179 else if ( ( strcmp("status", sys_file ) == 0 ) || strcmp("state", sys_file ) == 0 )
180 b->state = file_content;
181 else if ( strcmp("voltage_now", sys_file ) == 0 ) {
182 b->voltage = get_unit_value((gchar*) file_content) / 1000;
183 }
184
185 g_string_free( filename, TRUE );
186 }
187 i++;
188 }
189
190 /* convert energy values (in mWh) to charge values (in mAh) if needed and possible */
191 if (b->last_capacity_unit != -1 && b->last_capacity == -1) {
192 if (b->voltage != -1) {
193 b->last_capacity = b->last_capacity_unit * 1000 / b->voltage;
194 } else {
195 b->last_capacity = b->last_capacity_unit;
196 b->capacity_unit = "mWh";
197 }
198 }
199 if (b->design_capacity_unit != -1 && b->design_capacity == -1) {
200 if (b->voltage != -1) {
201 b->design_capacity = b->design_capacity_unit * 1000 / b->voltage;
202 } else {
203 b->design_capacity = b->design_capacity_unit;
204 b->capacity_unit = "mWh";
205 }
206 }
207 if (b->remaining_energy != -1 && b->remaining_capacity == -1) {
208 if (b->voltage != -1) {
209 b->remaining_capacity = b->remaining_energy * 1000 / b->voltage;
210 b->present_rate = b->present_rate * 1000 / b->voltage;
211 } else {
212 b->remaining_capacity = b->remaining_energy;
213 }
214 }
215 if (b->last_capacity < MIN_CAPACITY)
216 b->percentage = 0;
217 else
218 b->percentage = b->remaining_capacity * 100 / b->last_capacity;
219
220 if (b->percentage > 100)
221 b->percentage = 100;
222
223
224
225 if (b->present_rate == -1) {
226 b->poststr = "rate information unavailable";
227 b->seconds = -1;
228 } else if (!strcasecmp(b->state, "charging")) {
229 if (b->present_rate > MIN_PRESENT_RATE) {
230 b->seconds = 3600 * (b->last_capacity - b->remaining_capacity) / b->present_rate;
231 b->poststr = " until charged";
232 } else {
233 b->poststr = "charging at zero rate - will never fully charge.";
234 b->seconds = -1;
235 }
236 } else if (!strcasecmp(b->state, "discharging")) {
237 if (b->present_rate > MIN_PRESENT_RATE) {
238 b->seconds = 3600 * b->remaining_capacity / b->present_rate;
239 b->poststr = " remaining";
240 } else {
241 b->poststr = "discharging at zero rate - will never fully discharge.";
242 b->seconds = -1;
243 }
244 } else {
245 b->poststr = NULL;
246 b->seconds = -1;
247 }
248
249 }
250
251 static battery* acpi_sys_get_battery_from_dir (const gchar *device_name ) {
252 battery *b = battery_new();
253 b->path = g_strdup( device_name );
254 return b;
255 }
256
257 battery *battery_get() {
258 GError * error = NULL;
259 const gchar *entry;
260 GDir * dir = g_dir_open( ACPI_PATH_SYS_POWER_SUPPY, 0, &error );
261 battery *b = NULL;
262 if ( dir == NULL )
263 {
264 g_warning( "NO ACPI/sysfs support in kernel: %s", error->message );
265 return NULL;
266 }
267 while ( ( entry = g_dir_read_name (dir) ) != NULL )
268 {
269 b = acpi_sys_get_battery_from_dir(entry);
270 battery_update ( b );
271 if ( b->type_battery == TRUE )
272 break;
273 /* ignore non-batteries */
274 else
275 g_free(b);
276 }
277 g_dir_close( dir );
278 return b;
279 }
280
281 gboolean battery_is_charging( battery *b )
282 {
283 return ( strcasecmp( b->state, "Unknown" ) == 0 ||
284 strcasecmp( b->state, "Full" ) == 0
285 || strcasecmp( b->state, "Charging" ) == 0 );
286 }
287
288 gint battery_get_remaining( battery *b )
289 {
290 return b->seconds;
291 }
292
293