Remove initscripts and add PIDFile to service file
[platform/core/system/power-manager.git] / pm_battery.c
1 /*
2  * power-manager
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
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
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16 */
17
18 #include <glib.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include "pm_core.h"
24 #include "pm_battery.h"
25
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)*/
33
34 int (*get_battery_capacity)();
35
36 enum state_b {
37         B_UNCHARGING = 0,
38         B_CHARGING = 1,
39         B_END = 2
40 };
41
42 typedef struct _batt_node {
43         time_t clock;
44         int capacity;
45         struct _batt_node *preview;
46         struct _batt_node *next;
47 } Batt_node;
48
49 enum state_a {
50         A_TIMETOEMPTY = 0,
51         A_TIMETOFULL = 1,
52         A_END = 2
53 };
54
55 static int timeout_id = 0;
56 static int noti_fd = 0;
57
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};
66
67 static void print_all_batt_node(enum state_b b_index)
68 {
69         Batt_node *node = NULL;
70         int cnt = 0;
71
72         LOGINFO("print_all_batt_node [%d]", b_index);
73
74         if(b_index < 0 || b_index >= B_END)
75                 return;
76
77         if(batt_head[b_index] == NULL)
78                 return;
79
80         node = batt_head[b_index];
81         while(node != NULL) {
82                 cnt++;
83                 LOGINFO("[%d] capacity %5d, time %s", cnt, node->capacity,
84                                 ctime(&node->clock));
85                 node = node->next;
86         }
87 }
88
89 static int check_value_validity(enum state_b b_index,time_t clock,int capacity)
90 {
91         time_t old_clock = 0;
92         int old_capacity = 0;
93         int capadiff = 0;
94
95         if(b_index < 0 || b_index >= B_END)
96                 return -1;
97
98         if(batt_head[b_index] == NULL)
99                 return 0;
100
101         old_capacity = batt_head[b_index]->capacity;
102
103         if(system_wakeup_flag == true) {
104                 LOGERR("check value validity : invalid cuz system suspend!");
105                 system_wakeup_flag = false;
106                 return -1;
107         }
108         /* capacity */
109         capadiff = capacity - old_capacity;
110         if((capadiff * multiply_value[b_index]) <= 0) {
111                 LOGERR("check value validity : capadiff(%d) wrong!", capadiff);
112                 return -1;
113         }
114         return 0;
115 }
116
117 static int add_batt_node(enum state_b b_index, time_t clock, int capacity)
118 {
119         Batt_node *node = NULL;
120
121         PRINT_ALL_BATT_NODE(b_index);
122
123         if(b_index < 0 || b_index >= B_END)
124                 return -1;
125
126         node = (Batt_node *) malloc(sizeof(Batt_node));
127         if(node == NULL) {
128                 LOGERR("Not enough memory, add battery node fail!");
129                 return -1;
130         }
131
132         node->clock = clock;
133         node->capacity = capacity;
134
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;
138                 node->next = NULL;
139         } else {
140                 node->next = batt_head[b_index];
141                 node->preview = NULL;
142                 batt_head[b_index]->preview = node;
143                 batt_head[b_index] = node;
144         }
145         PRINT_ALL_BATT_NODE(b_index);
146         return 0;
147 }
148
149 static int reap_batt_node(enum state_b b_index, int max_count)
150 {
151         Batt_node *node = NULL;
152         Batt_node *tmp = NULL;
153         int cnt = 0;
154
155         PRINT_ALL_BATT_NODE(b_index);
156
157         if(b_index < 0 || b_index >= B_END)
158                 return -1;
159
160         if(max_count <= 0)
161                 return -1;
162
163         node = batt_head[b_index];
164
165         while(node != NULL) {
166                 if(cnt >= max_count) break;
167                 cnt++;
168                 node = node->next;
169         }
170
171         if(node != NULL && node != batt_tail[b_index]) {
172                 batt_tail[b_index] = node;
173                 node = node->next;
174                 batt_tail[b_index]->next = NULL;
175                 while(node != NULL) {
176                         tmp = node;
177                         node = node->next;
178                         free(tmp);
179                 }
180         }
181         PRINT_ALL_BATT_NODE(b_index);
182         return 0;
183 }
184
185 static int del_all_batt_node(enum state_b b_index)
186 {
187         Batt_node *node = NULL;
188
189         PRINT_ALL_BATT_NODE(b_index);
190
191         if(b_index < 0 || b_index >= B_END)
192                 return -1;
193         if(batt_head[b_index] == NULL)
194                 return 0;
195
196         while(batt_head[b_index] != NULL) {
197                 node = batt_head[b_index];
198                 batt_head[b_index] = batt_head[b_index]->next;
199                 free(node);
200         }
201         batt_tail[b_index] = NULL;
202         PRINT_ALL_BATT_NODE(b_index);
203         return 0;
204 }
205
206 static float update_factor(enum state_b b_index)
207 {
208         Batt_node *node = NULL;
209         double factor = 0.0;
210         double total_factor = 0.0;
211         int cnt = 0;
212         double timediff = 0.0;
213         double capadiff = 0.0;
214
215         if(b_index < 0 || b_index >= B_END)
216                 return 0;
217
218         if(batt_head[b_index] == NULL || batt_head[b_index]->next == NULL)
219                 return  avg_factor[b_index];
220
221         node = batt_head[b_index];
222         while(1) {
223                 timediff = difftime(node->clock, node->next->clock);
224                 capadiff = node->capacity - node->next->capacity;
225                 if(capadiff < 0)
226                         capadiff*=(-1);
227                 if(capadiff != 0)
228                         factor = timediff / capadiff;
229                 total_factor += factor;
230
231                 node = node->next;
232                 cnt++;
233
234                 /*LOGINFO("[%d] timediff(%lf) / capadiff(%lf) = factor(%lf)",
235                         cnt, timediff, capadiff, factor);*/
236                 factor = 0.0;
237
238                 if(node == NULL || node->next == NULL)
239                         break;
240                 if(cnt >= MAX_VALUE_COUNT[b_index]) {
241                         reap_batt_node(b_index, MAX_VALUE_COUNT[b_index]);
242                         break;
243                 }
244         }
245         LOGINFO(" sum = %lf", total_factor);
246         total_factor /= (float)cnt;
247         LOGINFO(" avg_factor = %lf", total_factor);
248
249         return total_factor;
250 }
251
252 static void update_time(enum state_a a_index, int seconds)
253 {
254         int clock;
255
256         if(a_index < 0 || a_index >= A_END)
257                 return;
258
259         if(seconds <= 0)
260                 return;
261
262         switch(a_index) {
263                 case A_TIMETOFULL:
264                         vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOFULL,
265                                 seconds);
266                         LOGINFO("update time[%d,%d]", a_index, seconds);
267                         break;
268                 case A_TIMETOEMPTY:
269                         vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOEMPTY,
270                                 seconds);
271                         LOGINFO("update time[%d,%d]", a_index, seconds);
272                         break;
273         }
274 }
275
276 void battinfo_calculation()
277 {
278         time_t clock;
279         int capacity = 0;
280         int estimated_time = 0;
281         int tmp = 0;
282
283         capacity = get_battery_capacity();
284
285         if(capacity <= 0)
286                 return;
287         if(capacity == old_capacity)
288                 return;
289
290         old_capacity = capacity;
291
292         if(get_charging_status(&tmp) == 0)
293                 charging_state = (tmp > 0 ? TRUE : FALSE);
294
295         clock = time(NULL);
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);
304                                 return;
305                         }
306                 }
307                 if(batt_head[B_CHARGING] == NULL) {
308                         add_batt_node(B_CHARGING, clock, capacity);
309                 } else {
310                         add_batt_node(B_CHARGING, clock, capacity);
311                         avg_factor[B_CHARGING] = update_factor(B_CHARGING);
312                 }
313                 estimated_time = (float)(full_capacity - capacity) *
314                                 avg_factor[B_CHARGING];
315                 update_time(A_TIMETOFULL, estimated_time);
316         } else {
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;
321                 }
322                 if(batt_head[B_UNCHARGING] == NULL) {
323                         add_batt_node(B_UNCHARGING, clock, capacity);
324                 } else {
325                         add_batt_node(B_UNCHARGING, clock, capacity);
326                         avg_factor[B_UNCHARGING] = update_factor(B_UNCHARGING);
327                 }
328                 estimated_time = (float)capacity * avg_factor[B_UNCHARGING];
329                 update_time(A_TIMETOEMPTY, estimated_time);
330         }
331 }
332
333 static gboolean battinfo_cb(gpointer data)
334 {
335         battinfo_calculation();
336         return TRUE;
337 }
338
339 static int init_battery_func()
340 {
341         int ret = -1;
342         int value = -1;
343
344         ret = battery_capacity_raw(&value);
345         if(ret >= 0) {
346                 get_battery_capacity = battery_capacity_raw;
347                 full_capacity = FULL_CAPACITY_RAW;
348                 LOGINFO("init_battery_func : full capacity(%d)", full_capacity);
349                 return 0;
350         }
351
352         ret = battery_capacity(&value);
353         if(ret >= 0) {
354                 get_battery_capacity = battery_capacity;
355                 full_capacity = FULL_CAPACITY;
356                 LOGINFO("init_battery_func : full capacity(%d)", full_capacity);
357                 return 0;
358         }
359
360         LOGERR("init_battery_func : fail to get battery info!");
361         return -1;
362 }
363
364 int start_battinfo_gathering(int timeout)
365 {
366         int ret;
367
368         LOGINFO("Start battery gathering!");
369
370         if(timeout < 0) {
371                 LOGERR("invalid timeout value [%d]!", timeout);
372                 return -1;
373         }
374         if(init_battery_func() != 0)
375                 return -1;
376
377         old_capacity = 0;
378         battinfo_calculation();
379
380         if(timeout > 0) {
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!");
389                         return -1;
390                 }
391                 ret = heynoti_subscribe(noti_fd, "device_charge_chgdet",
392                                 (void *)battinfo_calculation, (void *)NULL);
393                 if(ret != 0) {
394                         LOGERR("heynoti subscribe fail!");
395                         return -1;
396                 }
397
398                 ret = heynoti_attach_handler(noti_fd);
399                 if(ret != 0) {
400                         LOGERR("heynoti attach handler fail!");
401                         return -1;
402                 }
403         }
404         return 0;
405 }
406
407 void end_battinfo_gathering()
408 {
409         LOGINFO("End battery gathering!");
410
411         if(timeout_id > 0) {
412                 g_source_remove(timeout_id);
413                 timeout_id = 0;
414         }
415         if(noti_fd > 0) {
416                 heynoti_close(noti_fd);
417                 noti_fd = 0;
418         }
419
420         del_all_batt_node(B_UNCHARGING);
421         del_all_batt_node(B_CHARGING);
422 }
423