2e5dcc9037788d9cb9ed45edc0dffa20c7d6466c
[platform/core/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 "ss_device_plugin.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 static int battery_level_table[] = {
50         5,                      /* BATTERY_LEVEL0 */
51         15,                     /* 1 */
52         25,                     /* 2 */
53         40,                     /* 3 */
54         60,                     /* 4 */
55         80,                     /* 5 */
56         100,                    /* 6 */
57 };
58
59 #define _SYS_LOW_POWER "LOW_POWER"
60
61 struct lowbat_process_entry {
62         unsigned cur_bat_state;
63         unsigned new_bat_state;
64         int (*action) (void *);
65 };
66
67 static Ecore_Timer *lowbat_timer;
68 static int cur_bat_state = BATTERY_UNKNOWN;
69 static int cur_bat_capacity = -1;
70
71 static int bat_err_count = 0;
72
73 static int battery_warning_low_act(void *ad);
74 static int battery_critical_low_act(void *ad);
75 static int battery_power_off_act(void *ad);
76
77 static struct lowbat_process_entry lpe[] = {
78         {BATTERY_NORMAL, BATTERY_WARNING_LOW, battery_warning_low_act},
79         {BATTERY_WARNING_LOW, BATTERY_CRITICAL_LOW, battery_critical_low_act},
80         {BATTERY_CRITICAL_LOW,  BATTERY_POWER_OFF,              battery_critical_low_act},
81         {BATTERY_POWER_OFF,             BATTERY_REAL_POWER_OFF, battery_power_off_act},
82         {BATTERY_NORMAL, BATTERY_CRITICAL_LOW, battery_critical_low_act},
83         {BATTERY_WARNING_LOW,   BATTERY_POWER_OFF,              battery_critical_low_act},
84         {BATTERY_CRITICAL_LOW,  BATTERY_REAL_POWER_OFF, battery_power_off_act},
85         {BATTERY_NORMAL,                BATTERY_POWER_OFF,              battery_critical_low_act},
86         {BATTERY_WARNING_LOW,   BATTERY_REAL_POWER_OFF, battery_power_off_act},
87         {BATTERY_NORMAL,                BATTERY_REAL_POWER_OFF, battery_power_off_act},
88 };
89
90 static int battery_warning_low_act(void *data)
91 {
92         char lowbat_noti_name[NAME_MAX];
93
94         heynoti_get_snoti_name(_SYS_LOW_POWER, lowbat_noti_name, NAME_MAX);
95         ss_noti_send(lowbat_noti_name);
96
97         ss_action_entry_call_internal(PREDEF_LOWBAT, 1, WARNING_LOW_BAT_ACT);
98         return 0;
99 }
100
101 static int battery_critical_low_act(void *data)
102 {
103         ss_action_entry_call_internal(PREDEF_LOWBAT, 1, CRITICAL_LOW_BAT_ACT);
104         return 0;
105 }
106
107 static int battery_power_off_act(void *data)
108 {
109         ss_action_entry_call_internal(PREDEF_LOWBAT, 1, POWER_OFF_BAT_ACT);
110         return 0;
111 }
112
113 static int battery_charge_act(void *data)
114 {
115         return 0;
116 }
117
118 int ss_lowbat_set_charge_on(int onoff)
119 {
120         if(vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, onoff)!=0) {
121                 PRT_TRACE_ERR("fail to set charge vconf value");
122                 return -1;
123         }
124         return 0;
125 }
126
127 int ss_lowbat_is_charge_in_now()
128 {
129         int val = 0;
130         if (0 > plugin_intf->OEM_sys_get_battery_charge_now(&val)) {
131                 PRT_TRACE_ERR("fail to read charge now from kernel");
132                 ss_lowbat_set_charge_on(0);
133                 return 0;
134         }
135
136         if (val == 1) {
137                 ss_lowbat_set_charge_on(1);
138                 return 1;
139         } else {
140                 ss_lowbat_set_charge_on(0);
141                 return 0;
142         }
143 }
144
145 static int lowbat_process(int bat_percent, void *ad)
146 {
147         int new_bat_capacity;
148         int new_bat_state;
149         int vconf_state = -1;
150         int bat_full = -1;
151         int i, ret = 0;
152         int val = 0;
153         new_bat_capacity = bat_percent;
154         if (new_bat_capacity < 0)
155                 return -1;
156         if (new_bat_capacity != cur_bat_capacity) {
157                 PRT_TRACE("[BAT_MON] cur = %d new = %d", cur_bat_capacity, new_bat_capacity);
158                 if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, new_bat_capacity) == 0)
159                         cur_bat_capacity = new_bat_capacity;
160         }
161
162         if (0 > vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &vconf_state)) {
163                 PRT_TRACE_ERR("vconf_get_int() failed");
164                 return -1;
165         }
166
167         if (new_bat_capacity <= BATTERY_REAL_POWER_OFF) {
168                 if (0 > plugin_intf->OEM_sys_get_battery_charge_now(&val)) {
169                         PRT_TRACE_ERR("fail to read charge now from kernel");
170                 }
171                 PRT_TRACE("charge_now status %d",val);
172                 if (val == 1) {
173                         new_bat_state = BATTERY_POWER_OFF;
174                         if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
175                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_POWER_OFF);
176                 } else {
177                         new_bat_state = BATTERY_REAL_POWER_OFF;
178                         if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
179                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF);
180                 }
181         } else if (new_bat_capacity <= BATTERY_POWER_OFF) {
182                 new_bat_state = BATTERY_POWER_OFF;
183                 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
184                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_POWER_OFF);
185         } else if (new_bat_capacity <= BATTERY_CRITICAL_LOW) {
186                 new_bat_state = BATTERY_CRITICAL_LOW;
187                 if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
188                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_CRITICAL_LOW);
189         } else if (new_bat_capacity <= BATTERY_WARNING_LOW) {
190                 new_bat_state = BATTERY_WARNING_LOW;
191                 if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
192                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_WARNING_LOW);
193         } else {
194                 new_bat_state = BATTERY_NORMAL;
195                 if (new_bat_capacity == BATTERY_FULL) {
196                         plugin_intf->OEM_sys_get_battery_charge_full(&bat_full);
197                         if (bat_full == 1) {
198                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
199                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_FULL);
200                         } else {
201                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
202                                         ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_NORMAL);
203                         }
204                 } else {
205                         if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
206                                 ret=vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, VCONFKEY_SYSMAN_BAT_NORMAL);
207                 }
208         }
209
210         if(ret < 0)
211                 return -1;
212
213         ss_lowbat_is_charge_in_now();
214
215         if (cur_bat_state == new_bat_state) {
216                 return 0;
217         }
218
219         if (cur_bat_state == BATTERY_UNKNOWN) {
220                 for (i = 0;
221                      i < sizeof(lpe) / sizeof(struct lowbat_process_entry);
222                      i++) {
223                         if (new_bat_state == lpe[i].new_bat_state) {
224                                 lpe[i].action(ad);
225                                 cur_bat_state = new_bat_state;
226                                 return 0;
227                         }
228                 }
229         } else {
230                 for (i = 0;
231                      i < sizeof(lpe) / sizeof(struct lowbat_process_entry);
232                      i++) {
233                         if ((cur_bat_state == lpe[i].cur_bat_state)
234                             && (new_bat_state == lpe[i].new_bat_state)) {
235                                 lpe[i].action(ad);
236                                 cur_bat_state = new_bat_state;
237                                 return 0;
238                         }
239                 }
240         }
241         PRT_TRACE("[BATMON] Unknown battery state cur:%d new:%d",cur_bat_state,new_bat_state);
242         cur_bat_state = new_bat_state;
243         return -1;
244 }
245
246 static int lowbat_read()
247 {
248         int bat_percent;
249
250         plugin_intf->OEM_sys_get_battery_capacity(&bat_percent);
251
252         return bat_percent;
253 }
254
255 int ss_lowbat_monitor(void *data)
256 {
257         struct ss_main_data *ad = (struct ss_main_data *)data;
258         int bat_percent;
259
260         bat_percent = lowbat_read();
261         if (bat_percent < 0) {
262                 ecore_timer_interval_set(lowbat_timer, BAT_MON_INTERVAL_MIN);
263                 bat_err_count++;
264                 if (bat_err_count > MAX_BATTERY_ERROR) {
265                         PRT_TRACE_ERR
266                             ("[BATMON] Cannot read battery gage. stop read fuel gage");
267                         return 0;
268                 }
269                 return 1;
270         }
271         if (bat_percent > 100)
272                 bat_percent = 100;
273
274         if (lowbat_process(bat_percent, ad) < 0)
275                 ecore_timer_interval_set(lowbat_timer, BAT_MON_INTERVAL_MIN);
276         else
277                 ecore_timer_interval_set(lowbat_timer, BAT_MON_INTERVAL);
278
279         return 1;
280 }
281
282 static int wakeup_cb(keynode_t *key_nodes, void *data)
283 {
284         int pm_state = 0;
285
286         if ((pm_state =
287              vconf_keynode_get_int(key_nodes)) == VCONFKEY_PM_STATE_LCDOFF)
288                 ss_lowbat_monitor(NULL);
289
290         return 0;
291 }
292
293 /* for debugging (request by kernel) */
294 static int check_battery()
295 {
296         int r;
297         int ret = -1;
298
299         if (0 > plugin_intf->OEM_sys_get_battery_present(&ret)) {
300                 PRT_TRACE_ERR("[BATMON] battery check : %d", ret);
301         }
302         PRT_TRACE("[BATMON] battery check : %d", ret);
303
304         return ret;
305 }
306
307 int ss_lowbat_init(struct ss_main_data *ad)
308 {
309         int i;
310
311         /* need check battery */
312         lowbat_timer =
313             ecore_timer_add(BAT_MON_INTERVAL_MIN, ss_lowbat_monitor, ad);
314         ss_lowbat_is_charge_in_now();
315
316         vconf_notify_key_changed(VCONFKEY_PM_STATE, (void *)wakeup_cb, NULL);
317
318         return 0;
319 }