3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
24 #include "pm_device_plugin.h"
25 #include "pm_battery.h"
27 #define CHARGING_STATE(x) ((x) & CHRGR_FLAG)
28 #define FULL_CAPACITY_RAW (10000)
29 #define FULL_CAPACITY (100)
30 #define BATTERY_FULL_THRESHOLD (98)
31 #define MAX_COUNT_UNCHARGING (5)
32 #define MAX_COUNT_CHARGING (5)
33 #define PRINT_ALL_BATT_NODE(x) /*print_all_batt_node(x)*/
35 int (*get_battery_capacity)();
43 typedef struct _batt_node {
46 struct _batt_node *preview;
47 struct _batt_node *next;
56 static int timeout_id = 0;
57 static int noti_fd = 0;
59 static Batt_node *batt_head[B_END];
60 static Batt_node *batt_tail[B_END];
61 static int MAX_VALUE_COUNT[B_END] = {MAX_COUNT_UNCHARGING, MAX_COUNT_CHARGING};
62 static double avg_factor[B_END] = {-1.0, -1.0};
63 static int full_capacity = 0;
64 static int old_capacity = 0;
65 static int charging_state = 0;
66 static int multiply_value[B_END] = {-1, 1};
68 static void print_all_batt_node(enum state_b b_index)
70 Batt_node *node = NULL;
73 LOGINFO("print_all_batt_node [%d]", b_index);
75 if(b_index < 0 || b_index >= B_END)
78 if(batt_head[b_index] == NULL)
81 node = batt_head[b_index];
84 LOGINFO("[%d] capacity %5d, time %s", cnt, node->capacity,
90 static int check_value_validity(enum state_b b_index,time_t clock,int capacity)
96 if(b_index < 0 || b_index >= B_END)
99 if(batt_head[b_index] == NULL)
102 old_capacity = batt_head[b_index]->capacity;
104 if(system_wakeup_flag == true) {
105 LOGERR("check value validity : invalid cuz system suspend!");
106 system_wakeup_flag = false;
110 capadiff = capacity - old_capacity;
111 if((capadiff * multiply_value[b_index]) <= 0) {
112 LOGERR("check value validity : capadiff(%d) wrong!", capadiff);
118 static int add_batt_node(enum state_b b_index, time_t clock, int capacity)
120 Batt_node *node = NULL;
122 PRINT_ALL_BATT_NODE(b_index);
124 if(b_index < 0 || b_index >= B_END)
127 node = (Batt_node *) malloc(sizeof(Batt_node));
129 LOGERR("Not enough memory, add battery node fail!");
134 node->capacity = capacity;
136 if(batt_head[b_index] == NULL && batt_tail[b_index] == NULL) {
137 batt_head[b_index] = batt_tail[b_index] = node;
138 node->preview = NULL;
141 node->next = batt_head[b_index];
142 node->preview = NULL;
143 batt_head[b_index]->preview = node;
144 batt_head[b_index] = node;
146 PRINT_ALL_BATT_NODE(b_index);
150 static int reap_batt_node(enum state_b b_index, int max_count)
152 Batt_node *node = NULL;
153 Batt_node *tmp = NULL;
156 PRINT_ALL_BATT_NODE(b_index);
158 if(b_index < 0 || b_index >= B_END)
164 node = batt_head[b_index];
166 while(node != NULL) {
167 if(cnt >= max_count) break;
172 if(node != NULL && node != batt_tail[b_index]) {
173 batt_tail[b_index] = node;
175 batt_tail[b_index]->next = NULL;
176 while(node != NULL) {
182 PRINT_ALL_BATT_NODE(b_index);
186 static int del_all_batt_node(enum state_b b_index)
188 Batt_node *node = NULL;
190 PRINT_ALL_BATT_NODE(b_index);
192 if(b_index < 0 || b_index >= B_END)
194 if(batt_head[b_index] == NULL)
197 while(batt_head[b_index] != NULL) {
198 node = batt_head[b_index];
199 batt_head[b_index] = batt_head[b_index]->next;
202 batt_tail[b_index] = NULL;
203 PRINT_ALL_BATT_NODE(b_index);
207 static float update_factor(enum state_b b_index)
209 Batt_node *node = NULL;
211 double total_factor = 0.0;
213 double timediff = 0.0;
214 double capadiff = 0.0;
216 if(b_index < 0 || b_index >= B_END)
219 if(batt_head[b_index] == NULL || batt_head[b_index]->next == NULL)
220 return avg_factor[b_index];
222 node = batt_head[b_index];
224 timediff = difftime(node->clock, node->next->clock);
225 capadiff = node->capacity - node->next->capacity;
229 factor = timediff / capadiff;
230 total_factor += factor;
235 /*LOGINFO("[%d] timediff(%lf) / capadiff(%lf) = factor(%lf)",
236 cnt, timediff, capadiff, factor);*/
239 if(node == NULL || node->next == NULL)
241 if(cnt >= MAX_VALUE_COUNT[b_index]) {
242 reap_batt_node(b_index, MAX_VALUE_COUNT[b_index]);
246 LOGINFO(" sum = %lf", total_factor);
247 total_factor /= (float)cnt;
248 LOGINFO(" avg_factor = %lf", total_factor);
253 static void update_time(enum state_a a_index, int seconds)
257 if(a_index < 0 || a_index >= A_END)
265 vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOFULL,
267 LOGINFO("update time[%d,%d]", a_index, seconds);
270 vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOEMPTY,
272 LOGINFO("update time[%d,%d]", a_index, seconds);
277 void battinfo_calculation()
281 int estimated_time = 0;
284 capacity = get_battery_capacity();
288 if(capacity == old_capacity)
291 old_capacity = capacity;
293 if(get_charging_status(&tmp) == 0)
294 charging_state = (tmp > 0 ? TRUE : FALSE);
297 if(charging_state == TRUE) {
298 del_all_batt_node(B_UNCHARGING);
299 if((capacity * 100 / full_capacity)
300 >= BATTERY_FULL_THRESHOLD) {
301 if(battery_charge_full()) {
302 del_all_batt_node(B_CHARGING);
303 LOGINFO("battery fully charged!");
304 update_time(A_TIMETOFULL, 0);
308 if(batt_head[B_CHARGING] == NULL) {
309 add_batt_node(B_CHARGING, clock, capacity);
311 add_batt_node(B_CHARGING, clock, capacity);
312 avg_factor[B_CHARGING] = update_factor(B_CHARGING);
314 estimated_time = (float)(full_capacity - capacity) *
315 avg_factor[B_CHARGING];
316 update_time(A_TIMETOFULL, estimated_time);
318 del_all_batt_node(B_CHARGING);
319 if(system_wakeup_flag == true) {
320 del_all_batt_node(B_UNCHARGING);
321 system_wakeup_flag = false;
323 if(batt_head[B_UNCHARGING] == NULL) {
324 add_batt_node(B_UNCHARGING, clock, capacity);
326 add_batt_node(B_UNCHARGING, clock, capacity);
327 avg_factor[B_UNCHARGING] = update_factor(B_UNCHARGING);
329 estimated_time = (float)capacity * avg_factor[B_UNCHARGING];
330 update_time(A_TIMETOEMPTY, estimated_time);
334 static gboolean battinfo_cb(gpointer data)
336 battinfo_calculation();
340 static int init_battery_func()
345 ret = battery_capacity_raw(&value);
347 get_battery_capacity = battery_capacity_raw;
348 full_capacity = FULL_CAPACITY_RAW;
349 LOGINFO("init_battery_func : full capacity(%d)", full_capacity);
353 ret = battery_capacity(&value);
355 get_battery_capacity = battery_capacity;
356 full_capacity = FULL_CAPACITY;
357 LOGINFO("init_battery_func : full capacity(%d)", full_capacity);
361 LOGERR("init_battery_func : fail to get battery info!");
365 int start_battinfo_gathering(int timeout)
369 LOGINFO("Start battery gathering!");
372 LOGERR("invalid timeout value [%d]!", timeout);
375 if(init_battery_func() != 0)
379 battinfo_calculation();
382 /* Using g_timer for gathering battery info */
383 timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, timeout,
384 (GSourceFunc)battinfo_cb, NULL, NULL);
385 } else if(timeout == 0) {
386 /* Using heynoti from system-server(udev)
387 for gathering battery info */
388 if((noti_fd = heynoti_init()) < 0) {
389 LOGERR("heynoti init failed!");
392 ret = heynoti_subscribe(noti_fd, "device_charge_chgdet",
393 (void *)battinfo_calculation, (void *)NULL);
395 LOGERR("heynoti subscribe fail!");
399 ret = heynoti_attach_handler(noti_fd);
401 LOGERR("heynoti attach handler fail!");
408 void end_battinfo_gathering()
410 LOGINFO("End battery gathering!");
413 g_source_remove(timeout_id);
417 heynoti_close(noti_fd);
421 del_all_batt_node(B_UNCHARGING);
422 del_all_batt_node(B_CHARGING);