15 #include "logd-grabber.h"
18 static const char *vconf_power_mode_path = "db/setting/psmode";
19 static int min_term_predict_lifetime;
20 static time_t last_pm_time;
21 static int last_pm_level;
22 static enum logd_power_mode curr_power_mode;
24 static Eina_List *battery_check_points = NULL;
26 static int on_charge()
28 const char *charge_status_file = "/sys/class/power_supply/battery/status";
33 fp = fopen(charge_status_file, "r");
36 _E("fopen failed: %s", strerror(errno));
41 if (fscanf(fp, "%ms", &buf) < 0) {
43 _E("fscanf failed: %s", strerror(errno));
47 if (strcmp(buf, "Charging"))
54 _E("fopen failed: %s", strerror(errno));
60 static void power_mode_changed_cb(keynode_t *key, void *data)
62 int new_power_mode = (enum logd_power_mode)vconf_keynode_get_int(key);
64 if (logd_event(LOGD_POWER_MODE, LOGD_CHANGED, new_power_mode) !=
66 _E("logd_event failed");
72 last_pm_time = getSecTime();
73 last_pm_level = get_current_battery_level();
74 struct logd_battery_level *b;
78 min_term_predict_lifetime = config_get_int("min_term_predict_lifetime", 10800, NULL);
80 if (last_pm_level < 0) {
81 _E("get_current_battery_level failed, level set as 0");
84 b = (struct logd_battery_level*) calloc(1, sizeof(struct logd_battery_level));
87 _E("calloc failed: %s", strerror(errno));
91 b->date = last_pm_time;
92 b->level = last_pm_level;
94 battery_check_points = eina_list_append(battery_check_points, b);
95 if (eina_error_get()) {
96 _E("eina_list_append failed: %s", eina_error_msg_get(eina_error_get()));
101 is_on_charge = on_charge();
102 if (is_on_charge < 0) {
103 _E("on_charge failed");
105 } else if (is_on_charge > 0) {
106 curr_power_mode = LOGD_POWER_MODE_CHARGED;
108 if (vconf_get_int(vconf_power_mode_path, (int*)&curr_power_mode) < 0) {
109 _E("vconf_get_int failed: %s. Current power mode set as 0",
110 vconf_power_mode_path);
114 if (vconf_notify_key_changed(vconf_power_mode_path,
115 power_mode_changed_cb, NULL) < 0) {
116 _E("vconf_notify_key_changed failed: %s", vconf_power_mode_path);
122 int battery_level_changed_event_handler(struct logd_grabber_event *event)
124 struct logd_battery_level *b;
125 struct logd_battery_level *last_point;
127 int level = get_current_battery_level();
128 Eina_List *last_point_list = eina_list_last(battery_check_points);
129 time_t monotonic_time = getSecTime();
132 _E("get_current_battery_level failed");
136 last_point = (struct logd_battery_level*)eina_list_data_get(last_point_list);
137 if (level == last_point->level)
139 if (monotonic_time != last_point->date)
140 last_point->k = (float)(level - last_point->level) /
141 (monotonic_time - last_point->date);
143 last_point->k = level - last_point->level;
146 b = (struct logd_battery_level*) calloc(1, sizeof(struct logd_battery_level));
149 _E("calloc failed: %s", strerror(errno));
153 b->date = monotonic_time;
156 battery_check_points = eina_list_append(battery_check_points, b);
157 if (eina_error_get()) {
158 _E("eina_list_append failed: %s", eina_error_msg_get(eina_error_get()));
166 int battery_charger_event_handler(struct logd_grabber_event *event)
168 Eina_List *last_point_list = eina_list_last(battery_check_points);
169 struct logd_battery_level *last_point;
170 time_t monotonic_time = getSecTime();
171 time_t time_diff = monotonic_time - last_pm_time;
173 enum logd_power_mode new_power_mode;
175 last_point = (struct logd_battery_level*)eina_list_data_get(last_point_list);
176 level_diff = last_pm_level - last_point->level;
178 if (event->action == LOGD_ON)
179 new_power_mode = LOGD_POWER_MODE_CHARGED;
180 else if (event->action == LOGD_OFF) {
181 if (vconf_get_int(vconf_power_mode_path, (int*)&new_power_mode) < 0) {
182 _E("vconf_get_int failed");
185 store_new_power_mode(event->date, curr_power_mode, new_power_mode,
186 time_diff, level_diff);
187 curr_power_mode = new_power_mode;
188 last_pm_time = monotonic_time;
189 last_pm_level = last_point->level;
195 int battery_power_mode_changed_event_handler(struct logd_grabber_event *event)
197 Eina_List *last_point_list = eina_list_last(battery_check_points);
198 struct logd_battery_level *last_point;
199 enum logd_power_mode new_power_mode;
203 time_t monotonic_time = getSecTime();
205 time_diff = monotonic_time - last_pm_time;
206 last_point = (struct logd_battery_level*)eina_list_data_get(last_point_list);
207 level_diff = last_pm_level - last_point->level;
208 new_power_mode = (enum logd_power_mode) atoi(event->message);
210 ret = store_new_power_mode(event->date, curr_power_mode, new_power_mode,
211 time_diff, level_diff);
213 _E("store_new_power_mode failed");
217 curr_power_mode = new_power_mode;
218 last_pm_time = monotonic_time;
219 last_pm_level = last_point->level;
224 int battery_level_at(time_t date)
227 struct logd_battery_level *data;
228 struct logd_battery_level *nearest = NULL;
229 time_t diff = INT_MAX;
231 EINA_LIST_FOREACH(battery_check_points, l, data) {
232 int d = date - data->date;
234 if (d < diff && d >= 0) {
241 _E("have no enough data to return battery level at %d", date);
245 return (nearest->k * (date - nearest->date) + nearest->level);
248 int battery_send_check_points(int socket)
255 count = eina_list_count(battery_check_points);
256 if (write(socket, &count, sizeof(count)) != sizeof(count)) {
258 _E("write failed: %s", strerror(errno));
263 EINA_LIST_FOREACH(battery_check_points, l, data) {
264 if (write(socket, data, sizeof(struct logd_battery_level)) !=
265 sizeof(struct logd_battery_level)) {
267 _E("write failed: %s", strerror(errno));
275 int battery_send_estimate_lifetime(int socket)
277 int est_time[LOGD_POWER_MODE_MAX];
278 float curr_speed = -1;
279 float *avg_discharge_speed = NULL;
280 struct logd_battery_level *last_point = NULL;
281 struct logd_battery_level *pre_last_point = NULL;
287 points_number = eina_list_count(battery_check_points);
288 last_point = (struct logd_battery_level*)
289 eina_list_nth(battery_check_points, points_number - 1);
290 if (points_number > 1)
291 pre_last_point = (struct logd_battery_level*)
292 eina_list_nth(battery_check_points, points_number - 2);
294 for (i = 0; i < LOGD_POWER_MODE_MAX; ++i)
297 avg_discharge_speed = load_discharging_speed(min_term_predict_lifetime);
298 if (!avg_discharge_speed) {
299 _E("load_discharging_speed failed");
303 level = last_point->level;
305 if (points_number > 2 && curr_power_mode != LOGD_POWER_MODE_CHARGED &&
306 last_point->level < pre_last_point->level) {
307 curr_speed = -pre_last_point->k;
310 if (curr_speed > 0) {
311 for (i = 0; i < LOGD_POWER_MODE_MAX; ++i) {
312 est_time[i] = level / curr_speed;
313 if (avg_discharge_speed[curr_power_mode] > 0 && avg_discharge_speed[i] > 0)
314 est_time[i] *= avg_discharge_speed[i] /
315 avg_discharge_speed[curr_power_mode];
317 est_time[i] -= getSecTime() - last_point->date;
322 for (i = 0; i < LOGD_POWER_MODE_MAX; ++i) {
323 if (avg_discharge_speed[i] > 0)
324 est_time[i] = level * avg_discharge_speed[i];
328 free(avg_discharge_speed);
331 for (i = 0; i < LOGD_POWER_MODE_MAX; ++i) {
332 if (write(socket, &est_time[i], sizeof(est_time[i])) !=
333 sizeof(est_time[i])) {
335 _E("write failed: %s", strerror(errno));
348 if (battery_check_points) {
349 EINA_LIST_FOREACH(battery_check_points, l, data)
351 eina_list_free(battery_check_points);