1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail    : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <math.h>
21 #include <string.h>
22 #include <dirent.h>
23 #include <dbus/dbus-glib.h>
24 
25 #include "powermanager-draw.h"
26 #include "powermanager-struct.h"
27 #include "powermanager-common.h"
28 #include "powermanager-proc-acpi.h"
29 
30 #define CD_BATTERY_DIR "/proc/acpi/battery"
31 //#define CD_BATTERY_DIR "/home/fab/proc/acpi/battery"
32 
33 /*present: yes
34 capacity state: ok
35 charging state: discharging
36 present rate: 15000 mW
37 remaining capacity: 47040 mWh
38 present voltage: 15000 mV*/
39 
_find_battery_in_dir(const gchar * cBatteryPath)40 static gboolean _find_battery_in_dir (const gchar *cBatteryPath)
41 {
42 	// open the folder containing battery data.
43 	GDir *dir = g_dir_open (cBatteryPath, 0, NULL);
44 	if (dir == NULL)
45 	{
46 		cd_debug ("powermanager: no battery in %s",cBatteryPath );
47 		return FALSE;
48 	}
49 
50 	// parse the folder and search the battery files.
51 	GString *sBatteryInfoFilePath = g_string_new ("");
52 	gchar *cContent = NULL;
53 	gsize length=0;
54 	const gchar *cBatteryName;
55 	gboolean bBatteryFound = FALSE;
56 	do
57 	{
58 		cBatteryName = g_dir_read_name (dir);  // usually "BAT0".
59 		if (cBatteryName == NULL)
60 			break ;
61 
62 		// check the battery info.
63 		g_string_printf (sBatteryInfoFilePath, "%s/%s/info", cBatteryPath, cBatteryName);
64 		length=0;
65 		cd_debug ("  examen de la batterie '%s' ...", sBatteryInfoFilePath->str);
66 		g_file_get_contents (sBatteryInfoFilePath->str, &cContent, &length, NULL);
67 		if (cContent != NULL)
68 		{
69 			gchar *str = strchr (cContent, '\n');  // first line: "present:    yes"
70 			if (str != NULL)
71 			{
72 				gchar *str2 = strchr (str+1, ':');
73 				if (str2 != NULL)
74 				{
75 					str2 ++;
76 					myData.iCapacity = atoi (str2);
77 
78 					gchar *str3 = strchr (str2, ':');
79 					if (str3 != NULL)  // prefer the last full capacity if available.
80 					{
81 						str3 ++;
82 						myData.iCapacity = atoi (str3);
83 					}
84 
85 					cd_debug ("Capacity : %d mWsh", myData.iCapacity);
86 					myData.cBatteryStateFilePath = g_strdup_printf ("%s/%s/state", cBatteryPath, cBatteryName);
87 					bBatteryFound = TRUE;
88 				}
89 			}
90 			g_free (cContent);
91 		}
92 	}
93 	while (! bBatteryFound);
94 	g_dir_close (dir);
95 	return bBatteryFound;
96 }
cd_find_battery_proc_acpi(void)97 gboolean cd_find_battery_proc_acpi (void)
98 {
99 	gboolean bBatteryFound = _find_battery_in_dir (CD_BATTERY_DIR);
100 	return bBatteryFound;
101 }
102 
103 
104 #define go_to_next_line \
105 	cCurLine = strchr (cCurVal, '\n'); \
106 	g_return_val_if_fail (cCurLine != NULL, FALSE); \
107 	cCurLine ++; \
108 	cCurVal = cCurLine;
109 
110 #define jump_to_value \
111 	cCurVal = strchr (cCurLine, ':'); \
112 	g_return_val_if_fail (cCurVal != NULL, FALSE); \
113 	cCurVal ++; \
114 	while (*cCurVal == ' ') \
115 		cCurVal ++;
116 
cd_get_stats_from_proc_acpi(void)117 gboolean cd_get_stats_from_proc_acpi (void)
118 {
119 	//\_______________ get the content of the stats file.
120 	gchar *cContent = NULL;
121 	gsize length=0;
122 	GError *erreur = NULL;
123 	g_file_get_contents (myData.cBatteryStateFilePath, &cContent, &length, &erreur);
124 	if (erreur != NULL)
125 	{
126 		cd_warning ("powermanager : %s", erreur->message);
127 		g_error_free(erreur);
128 		erreur = NULL;
129 		return FALSE;
130 	}
131 	g_return_val_if_fail (cContent != NULL, FALSE);
132 
133 	gchar *cCurLine = cContent, *cCurVal = cContent;
134 
135 	//\_______________ check the battery presence.
136 	jump_to_value  // "present: yes"
137 	gboolean bBatteryPresent = (*cCurVal == 'y');
138 	if (bBatteryPresent != myData.bBatteryPresent)  // the battery has just been inserted/removed.
139 	{
140 		myData.bBatteryPresent = bBatteryPresent;
141 		if (! bBatteryPresent)  // if the battery has been removed, we are obviously on the sector.
142 		{
143 			cd_debug ("la batterie a ete enlevee\n");
144 			myData.bOnBattery = FALSE;
145 			update_icon();
146 			g_free (cContent);
147 			return TRUE;
148 		}
149 
150 		// reset the history.
151 		cd_debug ("la batterie a ete connectee\n");
152 		myData.iPrevTime = 0;
153 		myData.iPrevPercentage = 0;
154 		/**for (k = 0; k < PM_NB_VALUES; k ++)
155 			myData.fRateHistory[k] = 0;
156 		myData.iCurrentIndex = 0;
157 		myData.iIndexMax = 0;*/
158 		myData.iStatPercentageBegin = 0;
159 		myData.iStatPercentage = 0;
160 	}
161 
162 	go_to_next_line  // -> "capacity state: ok"
163 
164 	go_to_next_line  // -> "charging state: discharging"
165 
166 	//\_______________ check 'on battery' state.
167 	jump_to_value
168 	gboolean bOnBattery = (*cCurVal == 'd');  // "discharging"
169 	if (bOnBattery != myData.bOnBattery)  // state changed
170 	{
171 		/**for (k = 0; k < PM_NB_VALUES; k ++)  // reset the history.
172 			myData.fRateHistory[k] = 0;
173 		myData.iCurrentIndex = 0;
174 		myData.iIndexMax = 0;*/
175 		myData.iStatPercentageBegin = 0;
176 		myData.iStatPercentage = 0;
177 		myData.bOnBattery = bOnBattery;
178 	}
179 
180 	go_to_next_line  // -> present rate: 15000 mW
181 
182 	//\_______________ get the current charge and rate (this one can be 0 if not available).
183 	jump_to_value
184 	// double fPresentRate = atoi (cCurVal);  // 15000 mW OU 1400 mA
185 
186 	/*cCurVal ++;
187 	while (*cCurVal != ' ')
188 		cCurVal ++;
189 	while (*cCurVal == ' ')
190 		cCurVal ++;
191 	if (*cCurVal != 'm')
192 		cd_warning ("PowerManager : expecting mA or mW as the present rate unit");
193 	cCurVal ++;
194 	if (*cCurVal == 'W')
195 		bWatt = TRUE;
196 	else if (*cCurVal == 'A')
197 		bWatt = FALSE;
198 	else
199 		cd_warning ("PowerManager : expecting A or W as the present rate unit");*/
200 
201 	go_to_next_line  // -> "remaining capacity: 47040 mWh"
202 
203 	jump_to_value
204 	int iRemainingCapacity = atoi (cCurVal);  // 47040 mWh
205 
206 	/**go_to_next_line  // -> "present voltage: 15000 mV"
207 
208 	jump_to_value
209 	int iPresentVoltage = atoi (cCurVal);  // 15000 mV
210 	*/
211 	myData.iPercentage = 100. * iRemainingCapacity / myData.iCapacity;
212 	cd_debug ("myData.iPercentage : %.2f%% (%d / %d)", (double)myData.iPercentage, iRemainingCapacity, myData.iCapacity);
213 	if (myData.iPercentage > 100)
214 		myData.iPercentage = 100;
215 	if (myData.iPercentage < 0)
216 		myData.iPercentage = 0.;
217 
218 	//\_______________ now compute the time.
219 	myData.iTime = cd_estimate_time ();
220 
221 	//cd_message ("PowerManager : On Battery:%d ; iCapacity:%dmWh ; iRemainingCapacity:%dmWh ; fPresentRate:%.2fmW ; iPresentVoltage:%dmV", myData.bOnBattery, myData.iCapacity, iRemainingCapacity, fPresentRate, iPresentVoltage);
222 	g_free (cContent);
223 	return (TRUE);
224 }
225