shared: Replace device_notifier_type with the libsyscommon
[platform/core/system/deviced.git] / plugins / wearable / display / lbm.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdbool.h>
20 #include <math.h>
21 #include <hal/device/hal-display.h>
22 #include <libsyscommon/ini-parser.h>
23
24 #include "auto-brightness-sensorhub.h"
25 #include "lbm.h"
26 #include "display-info.h"
27 #include "core.h"
28 #include "device-interface.h"
29 #include "display-backlight.h"
30 #include "display-ops.h"
31 #include "shared/common.h"
32 #include "shared/device-notifier.h"
33 #include "shared/log.h"
34
35 #define SIGNAL_LBM_ON   "LBMOn"
36 #define SIGNAL_LBM_OFF  "LBMOff"
37
38 #define LCD_PHASED_DELAY                10000   /* microsecond */
39
40 #define LBM_TRANSIT_STEP                20
41
42 static struct lbm_config lbm_conf = {
43         .support = 0,
44         .down_level = 0,
45         .brt_table_size = 0,
46         .brt_table = NULL,
47         .aod_brightness_level = 0,
48 };
49
50 static struct display_backlight_ops *backlight_ops;
51 static int lbm_setting_mode;
52 static int system_brightness;
53 static bool display_dev_available = false;
54
55 static int (*origin_set_brightness)(int);
56
57 static void broadcast_lbm_state(int state)
58 {
59         char *str;
60
61         if (state == 1)
62                 str = SIGNAL_LBM_ON;
63         else
64                 str = SIGNAL_LBM_OFF;
65
66         gdbus_signal_emit(NULL,
67                         DEVICED_PATH_DISPLAY,
68                         DEVICED_INTERFACE_DISPLAY,
69                         str,
70                         NULL);
71 }
72
73 static int get_level_by_brt(int brt)
74 {
75         int iter;
76         for (iter = 0; iter < lbm_conf.brt_table_size; iter++) {
77                 if (lbm_conf.brt_table[iter] == brt)
78                         return iter;
79         }
80         return -EINVAL;
81 }
82
83 int lbm_down_brt(int brt)
84 {
85         int level;
86         int down_level;
87
88         if (lbm_conf.down_level == 0) {
89                 _I("LBM down level setting is 0.");
90                 return brt;
91         }
92
93         if (lbm_conf.brt_table == NULL || lbm_setting_mode == 0) {
94                 _I("LBM setting mode is %d.", lbm_setting_mode);
95                 return brt;
96         }
97
98         level = get_level_by_brt(brt);
99         down_level = level - lbm_conf.down_level;
100
101         if (down_level < 0)
102                 down_level = 0;
103
104         return lbm_conf.brt_table[down_level];
105 }
106
107 static int lbm_get_brightness(int *val)
108 {
109         *val = system_brightness;
110
111         return 0;
112 }
113
114 static int lbm_set_brightness(int val)
115 {
116         int brt = 0;
117
118         if(!display_dev_available) {
119                 _E("There is no display device.");
120                 return -ENOENT;
121         }
122
123         if (get_pm_status_flag() & DIM_MASK)
124                 val = 0;
125         else
126                 brt = lbm_down_brt(val);
127
128         system_brightness = val;
129
130         _I("Set brightness(LBM on) system=%d, real=%d.", val, brt);
131         syscommon_notifier_emit_notify(DEVICED_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
132
133         return hal_device_display_set_brightness(brt);
134 }
135
136 static void lbm_change_brightness(int start, int end, int step)
137 {
138         int diff, val;
139         int ret = -1;
140         int prev;
141
142         if (display_dimstay_check())
143                 return;
144
145         ret = display_backlight_get_brightness(&prev);
146
147         if (ret < 0) {
148                 _E("Failed to get brightness, %d.", ret);
149                 return;
150         }
151
152         if (prev == end)
153                 return;
154
155         if (get_pm_status_flag() & DIM_MASK)
156                 end = 0;
157
158         _I("Start %d, end %d, step %d.", start, end, step);
159
160         if (display_dev_available) {
161                 diff = lbm_down_brt(end);
162
163                 ret = hal_device_display_set_multi_brightness(diff, step, LCD_PHASED_DELAY);
164                 if (ret != -ENODEV) {
165                         if (ret < 0)
166                                 _E("Failed to set_multi_brightness, %d.", ret);
167
168                         display_backlight_set_brightness(end);
169
170                         return;
171                 }
172         }
173
174         diff = end - start;
175
176         if (abs(diff) < step)
177                 val = (diff > 0 ? 1 : -1);
178         else
179                 val = (int)ceil((double)diff / step);
180
181         while (start != end) {
182                 if (val == 0)
183                         break;
184
185                 start += val;
186                 if ((val > 0 && start > end) ||
187                     (val < 0 && start < end))
188                         start = end;
189
190                 usleep(LCD_PHASED_DELAY);
191                 display_backlight_set_brightness(start);
192         }
193 }
194
195 int lbm_set_state(int lbm)
196 {
197         _I("lbm_set_state, %d", lbm);
198
199         broadcast_lbm_state(lbm);
200         if (lbm) {
201                 origin_set_brightness = backlight_ops->set_brightness;
202                 backlight_ops->set_brightness = lbm_set_brightness;
203                 backlight_ops->get_brightness = lbm_get_brightness;
204                 backlight_ops->transit_brt = lbm_change_brightness;
205         } else {
206                 backlight_ops->set_brightness = origin_set_brightness;
207                 backlight_ops->get_brightness = NULL;
208                 backlight_ops->transit_brt = NULL;
209         }
210
211         return 0;
212 }
213
214 int lbm_get_state(void)
215 {
216         if (!lbm_conf.support)
217                 return -ENODEV;
218
219         return backlight_ops->set_brightness == lbm_set_brightness;
220 }
221
222 static void lbm_table_load(char *value, struct lbm_config *c)
223 {
224         char *p, *saveptr;
225         int level_count = 1;
226         int i;
227
228         if (!value || value[0] == '\0')
229                 return;
230
231         for (i = 0; *(value + i) != '\0'; i++) {
232                 if (*(value + i) == ',')
233                         level_count++;
234         }
235
236         c->brt_table = malloc(sizeof(int) * level_count);
237         if (!c->brt_table) {
238                 _E("Failed to allocate memory.");
239                 return;
240         }
241         c->brt_table_size = level_count;
242
243         i = 0;
244         p = strtok_r(value, ",", &saveptr);
245         if (p)
246                 c->brt_table[i++] = atoi(p);
247
248         while (p != NULL) {
249                 p = strtok_r(NULL, ",", &saveptr);
250                 if (p)
251                         c->brt_table[i++] = atoi(p);
252         }
253 }
254
255 static int lbm_load_config(struct parse_result *result, void *user_data)
256 {
257         struct lbm_config *c = user_data;
258
259         _D("%s,%s,%s.", result->section, result->name, result->value);
260
261         if (!c)
262                 return -EINVAL;
263
264         if (!MATCH(result->section, "Display"))
265                 return 0;
266
267         if (MATCH(result->name, "LBMsupport")) {
268                 c->support = (MATCH(result->value, "yes") ? 1 : 0);
269                 _D("lbm support is %d", c->support);
270         } else if (MATCH(result->name, "Level")) {
271                 SET_CONF(c->down_level, atoi(result->value));
272                 _D("lbm down level is %d", c->down_level);
273         } else if (MATCH(result->name, "BrtTable")) {
274                 lbm_table_load(result->value, c);
275                 _D("LBM table loaded.");
276         }
277
278         return 0;
279 }
280
281 static void lbm_mode_changed(keynode_t *key_nodes, void *data)
282 {
283         int mode = vconf_keynode_get_bool(key_nodes);
284
285         _I("LBM setting value is %s.", mode ? "enable" : "disable");
286
287         lbm_setting_mode = mode;
288
289         auto_brightness_control(BR_LBM_OFF, BR_IMPLICIT);
290 }
291
292 bool get_lbm_setting(void)
293 {
294         return lbm_setting_mode;
295 }
296
297 static GVariant *dbus_getlbm(GDBusConnection *conn,
298         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
299         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
300 {
301         int lbm;
302
303         lbm = lbm_get_state();
304         if (lbm < 0)
305                 _E("Failed to get low brightness mode %d.", lbm);
306         else
307                 _D("Get low brightness mode %d.", lbm);
308
309         return g_variant_new("(i)", lbm);
310 }
311
312 static const dbus_method_s dbus_methods[] = {
313         { "GetLBM",          NULL,   "i", dbus_getlbm },
314 };
315
316 static const dbus_interface_u dbus_interface = {
317         .oh = NULL,
318         .name = DEVICED_INTERFACE_DISPLAY,
319         .methods = dbus_methods,
320         .nr_methods = ARRAY_SIZE(dbus_methods),
321 };
322 static void lbm_init(void *data)
323 {
324         int ret;
325
326         /* load configutation */
327         ret = config_parse(DISPLAY_CONF_FILE, lbm_load_config, &lbm_conf);
328         if (ret < 0)
329                 _W("Failed to load %s, %d. Use default value.", DISPLAY_CONF_FILE, ret);
330
331         ret = vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_AUTOMATIC_LOW_BRIGHTNESS, &lbm_setting_mode);
332         if (ret < 0)
333                 _E("Failed to get VCONFKEY_SETAPPL_ACCESSIBILITY_AUTOMATIC_LOW_BRIGHTNESS, %d.", ret);
334
335         vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_AUTOMATIC_LOW_BRIGHTNESS, lbm_mode_changed, NULL);
336
337         ret = gdbus_add_object(NULL, DEVICED_PATH_DISPLAY, &dbus_interface);
338         if (ret < 0)
339                 _E("Failed to init dbus method, %d.", ret);
340
341         display_dev_available = display_is_hal_backend_available();
342
343         _I("LBM setting value is %d.", lbm_setting_mode);
344 }
345
346 static const struct display_ops display_lbm_ops = {
347         .name     = "lbm",
348         .init     = lbm_init,
349 };
350
351 DISPLAY_OPS_REGISTER(&display_lbm_ops)
352
353 static void __CONSTRUCTOR__ initialize(void)
354 {
355         backlight_ops = get_var_backlight_ops();
356         if (!backlight_ops)
357                 _E("Failed to get backlight operator variable.");
358 }