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