8999d5422b65189aa2f9a3bf61fec51997b018f6
[framework/system/system-server.git] / ss_lowbat_handler.c
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <assert.h>
19 #include <limits.h>
20 #include <heynoti.h>
21 #include <vconf.h>
22 #include <sysman.h>
23 #include <fcntl.h>
24
25 #include "ss_log.h"
26 #include "ss_launch.h"
27 #include "ss_noti.h"
28 #include "ss_queue.h"
29 #include "device-node.h"
30 #include "include/ss_data.h"
31
32 #define BAT_MON_INTERVAL                30
33 #define BAT_MON_INTERVAL_MIN            2
34
35 #define BATTERY_CHARGING                65535
36 #define BATTERY_UNKNOWN                 -1
37 #define BATTERY_FULL                    100
38 #define BATTERY_NORMAL                  100
39 #define BATTERY_WARNING_LOW             15
40 #define BATTERY_CRITICAL_LOW            5
41 #define BATTERY_POWER_OFF               1
42 #define BATTERY_REAL_POWER_OFF  0
43
44 #define MAX_BATTERY_ERROR               10
45 #define RESET_RETRY_COUNT               3
46
47 #define LOWBAT_EXEC_PATH                PREFIX"/bin/lowbatt-popup"
48
49 #define BATTERY_LEVEL_CHECK_FULL        95
50 #define BATTERY_LEVEL_CHECK_HIGH        15
51 #define BATTERY_LEVEL_CHECK_LOW         5
52 #define BATTERY_LEVEL_CHECK_CRITICAL    1
53
54 #define _SYS_LOW_POWER "LOW_POWER"
55
56 struct lowbat_process_entry {
57         unsigned cur_bat_state;
58         unsigned new_bat_state;
59         int (*action) (void *);
60 };
61
62 static Ecore_Timer *lowbat_timer;
63 static int cur_bat_state = BATTERY_UNKNOWN;
64 static int cur_bat_capacity = -1;
65
66 static int bat_err_count = 0;
67
68 static int battery_warning_low_act(void *ad);
69 static int battery_critical_low_act(void *ad);
70 static int battery_power_off_act(void *ad);
71
72 static struct lowbat_process_entry lpe[] = {
73         {BATTERY_NORMAL, BATTERY_WARNING_LOW, battery_warning_low_act},
74         {BATTERY_WARNING_LOW, BATTERY_CRITICAL_LOW, battery_critical_low_act},
75         {BATTERY_CRITICAL_LOW,  BATTERY_POWER_OFF,              battery_critical_low_act},
76         {BATTERY_POWER_OFF,             BATTERY_REAL_POWER_OFF, battery_power_off_act},
77         {BATTERY_NORMAL, BATTERY_CRITICAL_LOW, battery_critical_low_act},
78         {BATTERY_WARNING_LOW,   BATTERY_POWER_OFF,              battery_critical_low_act},
79         {BATTERY_CRITICAL_LOW,  BATTERY_REAL_POWER_OFF, battery_power_off_act},
80         {BATTERY_NORMAL,                BATTERY_POWER_OFF,              battery_critical_low_act},
81         {BATTERY_WARNING_LOW,   BATTERY_REAL_POWER_OFF, battery_power_off_act},
82         {BATTERY_NORMAL,                BATTERY_REAL_POWER_OFF, battery_power_off_act},
83 };
84
85 /*
86  * TODO: remove this function
87  */
88 static void print_lowbat_state(unsigned int bat_percent)
89 {
90 #if 0
91         int i;
92         for (i = 0; i < BAT_MON_SAMPLES; i++)
93                 PRT_TRACE("\t%d", recent_bat_percent[i]);
94 #endif
95 }
96
97 static int battery_warning_low_act(void *data)
98 {
99         char lowbat_noti_name[NAME_MAX];
100
101         heynoti_get_snoti_name(_SYS_LOW_POWER, lowbat_noti_name, NAME_MAX);
102         ss_noti_send(lowbat_noti_name);
103
104         ss_action_entry_call_internal(PREDEF_LOWBAT, 1, WARNING_LOW_BAT_ACT);
105         return 0;
106 }
107
108 static int battery_critical_low_act(void *data)
109 {
110         ss_action_entry_call_internal(PREDEF_LOWBAT, 1, CRITICAL_LOW_BAT_ACT);
111         return 0;
112 }
113
114 static int battery_power_off_act(void *data)
115 {
116         ss_action_entry_call_internal(PREDEF_LOWBAT, 1, POWER_OFF_BAT_ACT);
117         return 0;
118 }
119
120 static int battery_charge_act(void *data)
121 {
122         return 0;
123 }
124
125 int ss_lowbat_set_charge_on(int onoff)
126 {
127         if(vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, onoff)!=0) {
128                 PRT_TRACE_ERR("fail to set charge vconf value");
129                 return -1;
130         }
131         return 0;
132 }
133
134 int ss_lowbat_is_charge_in_now()
135 {
136         int val = 0;
137         if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_NOW, &val) < 0) {
138                 PRT_TRACE_ERR("fail to read charge now from kernel");
139                 ss_lowbat_set_charge_on(0);
140                 return 0;
141         }
142
143         if (val == 1) {
144                 ss_lowbat_set_charge_on(1);
145                 return 1;
146         } else {
147                 ss_lowbat_set_charge_on(0);
148                 return 0;
149         }
150 }
151
152 static int lowbat_process(int bat_percent, void *ad)
153 {
154         int new_bat_capacity;
155         int new_bat_state;
156         int vconf_state = -1;
157         int bat_full = -1;
158         int i, ret = 0;
159         int val = 0;
160         new_bat_capacity = bat_percent;
161         if (new_bat_capacity < 0)
162                 return -1;
163         if (new_bat_capacity != cur_bat_capacity) {
164                 PRT_TRACE("[BAT_MON] cur = %d new = %d", cur_bat_capacity, new_bat_capacity);
165                 if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, new_bat_capacity) == 0)
166                         cur_bat_capacity = new_bat_capacity;
167         }
168
169         if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &vconf_state) < 0) {
170                 PRT_TRACE_ERR("vconf_get_int() failed");
171                 return -1;
172         }
173
174         if (new_bat_capacity <= BATTERY_REAL_POWER_OFF) {
175                 if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_NOW, &val) < 0) {
176                         PRT_TRACE_ERR("fail to read charge now from kernel");
177                 }
178                 PRT_TRACE("charge_now status %d",val);
179                 if (val == 1) {
180                         new_bat_state = BATTERY_POWER_OFF;
181                         if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
182                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_POWER_OFF);
183                 } else {
184                         new_bat_state = BATTERY_REAL_POWER_OFF;
185                         if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
186                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF);
187                 }
188         } else if (new_bat_capacity <= BATTERY_POWER_OFF) {
189                 new_bat_state = BATTERY_POWER_OFF;
190                 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
191                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_POWER_OFF);
192         } else if (new_bat_capacity <= BATTERY_CRITICAL_LOW) {
193                 new_bat_state = BATTERY_CRITICAL_LOW;
194                 if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
195                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_CRITICAL_LOW);
196         } else if (new_bat_capacity <= BATTERY_WARNING_LOW) {
197                 new_bat_state = BATTERY_WARNING_LOW;
198                 if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
199                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_WARNING_LOW);
200         } else {
201                 new_bat_state = BATTERY_NORMAL;
202                 if (new_bat_capacity == BATTERY_FULL) {
203                         if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_FULL, &bat_full) < 0) {
204                                 PRT_TRACE_ERR("fail to read charge full from kernel");
205                         }
206                         if (bat_full == 1) {
207                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
208                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_FULL);
209                         } else {
210                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
211                                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_NORMAL);
212                         }
213                 } else {
214                         if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
215                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_NORMAL);
216                 }
217         }
218
219         if(ret < 0)
220                 return -1;
221
222         ss_lowbat_is_charge_in_now();
223
224         if (cur_bat_state == new_bat_state) {
225                 return 0;
226         }
227
228         if (cur_bat_state == BATTERY_UNKNOWN) {
229                 for (i = 0;
230                      i < sizeof(lpe) / sizeof(struct lowbat_process_entry);
231                      i++) {
232                         if (new_bat_state == lpe[i].new_bat_state) {
233                                 lpe[i].action(ad);
234                                 cur_bat_state = new_bat_state;
235                                 return 0;
236                         }
237                 }
238         } else {
239                 for (i = 0;
240                      i < sizeof(lpe) / sizeof(struct lowbat_process_entry);
241                      i++) {
242                         if ((cur_bat_state == lpe[i].cur_bat_state)
243                             && (new_bat_state == lpe[i].new_bat_state)) {
244                                 lpe[i].action(ad);
245                                 cur_bat_state = new_bat_state;
246                                 return 0;
247                         }
248                 }
249         }
250         PRT_TRACE("[BATMON] Unknown battery state cur:%d new:%d",cur_bat_state,new_bat_state);
251         cur_bat_state = new_bat_state;
252         return -1;
253 }
254
255 static int lowbat_read()
256 {
257         int bat_percent;
258
259         if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CAPACITY, &bat_percent) < 0) {
260                 PRT_TRACE_ERR("fail to read power capacity from kernel");
261                 return -1;
262         }
263
264         return bat_percent;
265 }
266
267 static void __ss_change_lowbat_level(int bat_percent)
268 {
269         int prev, now;
270
271         if (cur_bat_capacity == bat_percent)
272                 return;
273
274         if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, &prev) < 0) {
275                 PRT_TRACE_ERR("vconf_get_int() failed");
276                 return;
277         }
278
279
280         if (bat_percent > BATTERY_LEVEL_CHECK_FULL) {
281                 now = VCONFKEY_SYSMAN_BAT_LEVEL_FULL;
282         } else if (bat_percent > BATTERY_LEVEL_CHECK_HIGH) {
283                 now = VCONFKEY_SYSMAN_BAT_LEVEL_HIGH;
284         } else if (bat_percent > BATTERY_LEVEL_CHECK_LOW) {
285                 now = VCONFKEY_SYSMAN_BAT_LEVEL_LOW;
286         } else if (bat_percent > BATTERY_LEVEL_CHECK_CRITICAL) {
287                 now = VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL;
288         } else {
289                 now = VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY;
290         }
291
292         if (prev != now)
293                 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, now);
294 }
295
296 static int __check_lowbat_percent(void)
297 {
298         int bat_percent;
299
300         bat_percent = lowbat_read();
301         if (bat_percent < 0) {
302                 ecore_timer_interval_set(lowbat_timer, BAT_MON_INTERVAL_MIN);
303                 bat_err_count++;
304                 if (bat_err_count > MAX_BATTERY_ERROR) {
305                         PRT_TRACE_ERR
306                             ("[BATMON] Cannot read battery gage. stop read fuel gage");
307                         return 0;
308                 }
309                 return 1;
310         }
311         if (bat_percent > 100)
312                 bat_percent = 100;
313         __ss_change_lowbat_level(bat_percent);
314         return bat_percent;
315 }
316
317 int ss_lowbat_monitor(void *data)
318 {
319         int bat_percent;
320         struct ss_main_data *ad = (struct ss_main_data *)data;
321
322         bat_percent = __check_lowbat_percent();
323         print_lowbat_state(bat_percent);
324
325         if (lowbat_process(bat_percent, ad) < 0)
326                 ecore_timer_interval_set(lowbat_timer, BAT_MON_INTERVAL_MIN);
327         else
328                 ecore_timer_interval_set(lowbat_timer, BAT_MON_INTERVAL);
329
330         return 1;
331 }
332
333 static int wakeup_cb(keynode_t *key_nodes, void *data)
334 {
335         int pm_state = 0;
336
337         if ((pm_state =
338              vconf_keynode_get_int(key_nodes)) == VCONFKEY_PM_STATE_LCDOFF)
339                 ss_lowbat_monitor(NULL);
340
341         return 0;
342 }
343
344 /* for debugging (request by kernel) */
345 static int check_battery()
346 {
347         int r;
348         int ret = -1;
349
350         if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_PRESENT, &ret) < 0) {
351                 PRT_TRACE_ERR("[BATMON] battery check : %d", ret);
352         }
353         PRT_TRACE("[BATMON] battery check : %d", ret);
354
355         return ret;
356 }
357
358 int ss_lowbat_init(struct ss_main_data *ad)
359 {
360         int i;
361
362         /* need check battery */
363         lowbat_timer =
364                 ecore_timer_add(BAT_MON_INTERVAL_MIN, ss_lowbat_monitor, ad);
365
366         __check_lowbat_percent();
367
368         ss_lowbat_is_charge_in_now();
369
370         vconf_notify_key_changed(VCONFKEY_PM_STATE, (void *)wakeup_cb, NULL);
371
372         return 0;
373 }