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_battery.h"
26 #define CHARGING_STATE(x) ((x) & CHRGR_FLAG)
27 #define FULL_CAPACITY_RAW (10000)
28 #define FULL_CAPACITY (100)
29 #define BATTERY_FULL_THRESHOLD (98)
30 #define MAX_COUNT_UNCHARGING (5)
31 #define MAX_COUNT_CHARGING (5)
32 #define PRINT_ALL_BATT_NODE(x) /*print_all_batt_node(x)*/
34 int (*get_battery_capacity)();
42 typedef struct _batt_node {
45 struct _batt_node *preview;
46 struct _batt_node *next;
55 static int timeout_id = 0;
56 static int noti_fd = 0;
58 static Batt_node *batt_head[B_END];
59 static Batt_node *batt_tail[B_END];
60 static int MAX_VALUE_COUNT[B_END] = {MAX_COUNT_UNCHARGING, MAX_COUNT_CHARGING};
61 static double avg_factor[B_END] = {-1.0, -1.0};
62 static int full_capacity = 0;
63 static int old_capacity = 0;
64 static int charging_state = 0;
65 static int multiply_value[B_END] = {-1, 1};
67 static void print_all_batt_node(enum state_b b_index)
69 Batt_node *node = NULL;
72 LOGINFO("print_all_batt_node [%d]", b_index);
74 if(b_index < 0 || b_index >= B_END)
77 if(batt_head[b_index] == NULL)
80 node = batt_head[b_index];
83 LOGINFO("[%d] capacity %5d, time %s", cnt, node->capacity,
89 static int check_value_validity(enum state_b b_index,time_t clock,int capacity)
95 if(b_index < 0 || b_index >= B_END)
98 if(batt_head[b_index] == NULL)
101 old_capacity = batt_head[b_index]->capacity;
103 if(system_wakeup_flag == true) {
104 LOGERR("check value validity : invalid cuz system suspend!");
105 system_wakeup_flag = false;
109 capadiff = capacity - old_capacity;
110 if((capadiff * multiply_value[b_index]) <= 0) {
111 LOGERR("check value validity : capadiff(%d) wrong!", capadiff);
117 static int add_batt_node(enum state_b b_index, time_t clock, int capacity)
119 Batt_node *node = NULL;
121 PRINT_ALL_BATT_NODE(b_index);
123 if(b_index < 0 || b_index >= B_END)
126 node = (Batt_node *) malloc(sizeof(Batt_node));
128 LOGERR("Not enough memory, add battery node fail!");
133 node->capacity = capacity;
135 if(batt_head[b_index] == NULL && batt_tail[b_index] == NULL) {
136 batt_head[b_index] = batt_tail[b_index] = node;
137 node->preview = NULL;
140 node->next = batt_head[b_index];
141 node->preview = NULL;
142 batt_head[b_index]->preview = node;
143 batt_head[b_index] = node;
145 PRINT_ALL_BATT_NODE(b_index);
149 static int reap_batt_node(enum state_b b_index, int max_count)
151 Batt_node *node = NULL;
152 Batt_node *tmp = NULL;
155 PRINT_ALL_BATT_NODE(b_index);
157 if(b_index < 0 || b_index >= B_END)
163 node = batt_head[b_index];
165 while(node != NULL) {
166 if(cnt >= max_count) break;
171 if(node != NULL && node != batt_tail[b_index]) {
172 batt_tail[b_index] = node;
174 batt_tail[b_index]->next = NULL;
175 while(node != NULL) {
181 PRINT_ALL_BATT_NODE(b_index);
185 static int del_all_batt_node(enum state_b b_index)
187 Batt_node *node = NULL;
189 PRINT_ALL_BATT_NODE(b_index);
191 if(b_index < 0 || b_index >= B_END)
193 if(batt_head[b_index] == NULL)
196 while(batt_head[b_index] != NULL) {
197 node = batt_head[b_index];
198 batt_head[b_index] = batt_head[b_index]->next;
201 batt_tail[b_index] = NULL;
202 PRINT_ALL_BATT_NODE(b_index);
206 static float update_factor(enum state_b b_index)
208 Batt_node *node = NULL;
210 double total_factor = 0.0;
212 double timediff = 0.0;
213 double capadiff = 0.0;
215 if(b_index < 0 || b_index >= B_END)
218 if(batt_head[b_index] == NULL || batt_head[b_index]->next == NULL)
219 return avg_factor[b_index];
221 node = batt_head[b_index];
223 timediff = difftime(node->clock, node->next->clock);
224 capadiff = node->capacity - node->next->capacity;
228 factor = timediff / capadiff;
229 total_factor += factor;
234 /*LOGINFO("[%d] timediff(%lf) / capadiff(%lf) = factor(%lf)",
235 cnt, timediff, capadiff, factor);*/
238 if(node == NULL || node->next == NULL)
240 if(cnt >= MAX_VALUE_COUNT[b_index]) {
241 reap_batt_node(b_index, MAX_VALUE_COUNT[b_index]);
245 LOGINFO(" sum = %lf", total_factor);
246 total_factor /= (float)cnt;
247 LOGINFO(" avg_factor = %lf", total_factor);
252 static void update_time(enum state_a a_index, int seconds)
256 if(a_index < 0 || a_index >= A_END)
264 vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOFULL,
266 LOGINFO("update time[%d,%d]", a_index, seconds);
269 vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOEMPTY,
271 LOGINFO("update time[%d,%d]", a_index, seconds);
276 void battinfo_calculation()
280 int estimated_time = 0;
283 capacity = get_battery_capacity();
287 if(capacity == old_capacity)
290 old_capacity = capacity;
292 if(get_charging_status(&tmp) == 0)
293 charging_state = (tmp > 0 ? TRUE : FALSE);
296 if(charging_state == TRUE) {
297 del_all_batt_node(B_UNCHARGING);
298 if((capacity * 100 / full_capacity)
299 >= BATTERY_FULL_THRESHOLD) {
300 if(battery_charge_full()) {
301 del_all_batt_node(B_CHARGING);
302 LOGINFO("battery fully charged!");
303 update_time(A_TIMETOFULL, 0);
307 if(batt_head[B_CHARGING] == NULL) {
308 add_batt_node(B_CHARGING, clock, capacity);
310 add_batt_node(B_CHARGING, clock, capacity);
311 avg_factor[B_CHARGING] = update_factor(B_CHARGING);
313 estimated_time = (float)(full_capacity - capacity) *
314 avg_factor[B_CHARGING];
315 update_time(A_TIMETOFULL, estimated_time);
317 del_all_batt_node(B_CHARGING);
318 if(system_wakeup_flag == true) {
319 del_all_batt_node(B_UNCHARGING);
320 system_wakeup_flag = false;
322 if(batt_head[B_UNCHARGING] == NULL) {
323 add_batt_node(B_UNCHARGING, clock, capacity);
325 add_batt_node(B_UNCHARGING, clock, capacity);
326 avg_factor[B_UNCHARGING] = update_factor(B_UNCHARGING);
328 estimated_time = (float)capacity * avg_factor[B_UNCHARGING];
329 update_time(A_TIMETOEMPTY, estimated_time);
333 static gboolean battinfo_cb(gpointer data)
335 battinfo_calculation();
339 static int init_battery_func()
344 ret = battery_capacity_raw(&value);
346 get_battery_capacity = battery_capacity_raw;
347 full_capacity = FULL_CAPACITY_RAW;
348 LOGINFO("init_battery_func : full capacity(%d)", full_capacity);
352 ret = battery_capacity(&value);
354 get_battery_capacity = battery_capacity;
355 full_capacity = FULL_CAPACITY;
356 LOGINFO("init_battery_func : full capacity(%d)", full_capacity);
360 LOGERR("init_battery_func : fail to get battery info!");
364 int start_battinfo_gathering(int timeout)
368 LOGINFO("Start battery gathering!");
371 LOGERR("invalid timeout value [%d]!", timeout);
374 if(init_battery_func() != 0)
378 battinfo_calculation();
381 /* Using g_timer for gathering battery info */
382 timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, timeout,
383 (GSourceFunc)battinfo_cb, NULL, NULL);
384 } else if(timeout == 0) {
385 /* Using heynoti from system-server(udev)
386 for gathering battery info */
387 if((noti_fd = heynoti_init()) < 0) {
388 LOGERR("heynoti init failed!");
391 ret = heynoti_subscribe(noti_fd, "device_charge_chgdet",
392 (void *)battinfo_calculation, (void *)NULL);
394 LOGERR("heynoti subscribe fail!");
398 ret = heynoti_attach_handler(noti_fd);
400 LOGERR("heynoti attach handler fail!");
407 void end_battinfo_gathering()
409 LOGINFO("End battery gathering!");
412 g_source_remove(timeout_id);
416 heynoti_close(noti_fd);
420 del_all_batt_node(B_UNCHARGING);
421 del_all_batt_node(B_CHARGING);