From: Youngjae Cho Date: Wed, 4 Sep 2019 12:16:36 +0000 (+0900) Subject: Add HBM, LBM module X-Git-Tag: accepted/tizen/unified/20190911.111739^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2599a3645f7550b10cc6f0c0a1c7408c2309b148;p=platform%2Fcore%2Fsystem%2Fdeviced.git Add HBM, LBM module Change-Id: I64a3090092f622f879d2c754e71b5354682936c6 Signed-off-by: Youngjae Cho --- diff --git a/conf/org.tizen.system.deviced.conf b/conf/org.tizen.system.deviced.conf index 0fa137a..5ef074e 100644 --- a/conf/org.tizen.system.deviced.conf +++ b/conf/org.tizen.system.deviced.conf @@ -18,6 +18,7 @@ + diff --git a/conf/wearable-display.conf b/conf/wearable-display.conf index f17b4ca..a3393ea 100644 --- a/conf/wearable-display.conf +++ b/conf/wearable-display.conf @@ -40,4 +40,9 @@ ControlDisplay=no PowerKeyDoublePressSupport=yes AccelSensorOn=no ContinuousSampling=no -Dimming=no \ No newline at end of file +Dimming=no +LBMsupport=yes +Level=4 +BrtTable=1,20,40,50,60,70,80,90,95,100 +AodBrightnessLevel=40 + diff --git a/plugins/wearable/display/auto-brightness-sensorhub.c b/plugins/wearable/display/auto-brightness-sensorhub.c new file mode 100644 index 0000000..6e96daf --- /dev/null +++ b/plugins/wearable/display/auto-brightness-sensorhub.c @@ -0,0 +1,202 @@ +/* + * deviced + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hbm.h" +#include "lbm.h" +#include "auto-brightness-sensorhub.h" +#include "display/util.h" +#include "display/core.h" +#include "display/display-ops.h" +#include "core/device-notifier.h" +#include "battery/power-supply.h" + +#define SPECIFIC_MODE_OFF 0 +#define LBM_LEVEL 110 +#define HBM_LEVEL 120 + +#define LOWBATCAPACITY 5 + +static int auto_brightness_state = SETTING_BRIGHTNESS_AUTOMATIC_OFF; + +static void change_brightness_transit(int start, int end) +{ + backlight_ops.transit_brt(start, end, + display_conf.brightness_change_step); +} + +static void set_brightness_level(int level) +{ + int old_level = 0; + if (pm_cur_state != S_NORMAL) + return; +/* + if (battery.capacity <= LOWBATCAPACITY && battery.charge_now != CHARGER_CHARGING) + return; +*/ + _I("level changed! %d", level); + + if ((level > PM_MAX_BRIGHTNESS || level < PM_MIN_BRIGHTNESS) && + (level != LBM_LEVEL && level != HBM_LEVEL && level != SPECIFIC_MODE_OFF)) { + _E("Invalid level %d", level); + return; + } + + backlight_ops.get_brightness(&old_level); + + switch (level) { + case LBM_LEVEL: + /* + * received LBM enable + * change brightness to under LBM_BRIGHTNESS_LOW and set lbm state + */ + if (hbm_get_state()) { + hbm_set_state(false); + _I("HBM mode disabled."); + } + if (!lbm_get_state()) { + lbm_set_state(true); + _I("LBM mode enabled."); + } + break; + case HBM_LEVEL: + /* HBM must do not turn on at DIM_STY state. */ + if (pm_status_flag & DIM_MASK) + break; + + /* + * received HBM enable + * change brightness to MAX value and set hbm state + */ + if (lbm_get_state()) { + lbm_set_state(false); + _I("Disabling LBM before enabling HBM."); + } + + change_brightness_transit(old_level, PM_MAX_BRIGHTNESS); + hbm_set_state(true); + _I("HBM mode enabled."); + + break; + case SPECIFIC_MODE_OFF: + /* + * received HBM disable + * unset hbm state and change brightness to setting value + */ + + level = backlight_ops.get_default_brt(); + + if (hbm_get_state()) + hbm_set_state(false); + + if (lbm_get_state()) + lbm_set_state(false); + + change_brightness_transit(old_level, level); + + break; + default: + /* + * received automatic brightness by the light sensor + */ + if (auto_brightness_state != SETTING_BRIGHTNESS_AUTOMATIC_ON) + return; + + if (hbm_get_state()) + hbm_set_state(false); + + if (lbm_get_state()) + lbm_set_state(false); + + if (old_level != level) { + change_brightness_transit(old_level, level); + backlight_ops.set_default_brt(level); + } + + break; + } + + device_notify(DEVICE_NOTIFIER_LCD_AUTOBRT_SENSING, NULL); +} + +static void set_default_brightness(void) +{ + int default_brt; + + default_brt = backlight_ops.get_default_brt(); + backlight_ops.set_default_brt(default_brt); + backlight_ops.update(); +} + +static void set_automatic_state_cb(keynode_t *key_nodes, void *data) +{ + if (key_nodes == NULL) { + _E("Wrong parameter, key_nodes is null."); + return; + } + auto_brightness_state = vconf_keynode_get_int(key_nodes); + + switch (auto_brightness_state) { + case SETTING_BRIGHTNESS_AUTOMATIC_OFF: + if (hbm_get_state()) + hbm_set_state(false); + /* escape dim state if it's in low battery.*/ + set_brightness_changed_state(); + set_default_brightness(); + break; + case SETTING_BRIGHTNESS_AUTOMATIC_PAUSE: + if (hbm_get_state()) + hbm_set_state(false); + break; + case SETTING_BRIGHTNESS_AUTOMATIC_ON: + set_brightness_changed_state(); + break; + default: + _E("Invalid value %d.", auto_brightness_state); + } +} + +int prepare_level_handler(void) +{ + int status, ret; + + display_info.set_brightness_level = set_brightness_level; + + ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &status); + if (ret >= 0) + auto_brightness_state = status; + + vconf_notify_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, + set_automatic_state_cb, NULL); + + return 0; +} + +void exit_level_handler(void) +{ + vconf_ignore_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, + set_automatic_state_cb); + set_default_brightness(); +} diff --git a/plugins/wearable/display/auto-brightness-sensorhub.h b/plugins/wearable/display/auto-brightness-sensorhub.h new file mode 100644 index 0000000..56243fb --- /dev/null +++ b/plugins/wearable/display/auto-brightness-sensorhub.h @@ -0,0 +1,30 @@ +/* + * deviced + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @file auto-brightness-sensorhub.h + * @brief auto-brightness-sensorhub header file + */ +#ifndef __AUTO_BRT_SENSORHUB_H__ +#define __AUTO_BRT_SENSORHUB_H__ + +int prepare_level_handler(void); +void exit_level_handler(void); + +#endif diff --git a/plugins/wearable/display/display-handler.c b/plugins/wearable/display/display-handler.c new file mode 100644 index 0000000..11226c6 --- /dev/null +++ b/plugins/wearable/display/display-handler.c @@ -0,0 +1,110 @@ +/* + * deviced + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "auto-brightness-sensorhub.h" +#include "core/device-notifier.h" +#include "display/util.h" +#include "display/core.h" +#include "display/poll.h" +#include "core/common.h" +#include "core/devices.h" +#include "display/display-actor.h" +#include "display/display-ops.h" +#include "display-info.h" + +#define CHARGER_LCD_NODE "/sys/class/power_supply/battery/lcd" + +enum charging_lcd_state { + CHARGING_LCD_OFF = 0, + CHARGING_LCD_ON = 1, +}; + +static GVariant *dbus_autobrightnesschanged(GDBusConnection *conn, + const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, + GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) +{ + int ret = 0; + int level; + + g_variant_get(param, "(i)", &level); + + if (display_info.set_brightness_level) + display_info.set_brightness_level(level); + else + ret = -ENOTSUP; + + return g_variant_new("(i)", ret); +} + +static const dbus_method_s dbus_methods[] = { + { "AutoBrightnessChanged", "i", "i", dbus_autobrightnesschanged }, +}; + +static const dbus_interface_u dbus_interface = { + .oh = NULL, + .name = DEVICED_INTERFACE_DISPLAY, + .methods = dbus_methods, + .nr_methods = ARRAY_SIZE(dbus_methods), +}; + +static int display_state_changed(void *data) +{ + enum state_t state; + int ret = 0; + + state = DATA_VALUE_INT(data); + + if (state == S_LCDON) + ret = sys_set_int(CHARGER_LCD_NODE, CHARGING_LCD_ON); + else + ret = sys_set_int(CHARGER_LCD_NODE, CHARGING_LCD_OFF); + + if (ret < 0) + _E("Can't write %s node %d.", CHARGER_LCD_NODE, state); + + return 0; +} + +static void display_handler_init(void *data) +{ + int ret; + + prepare_level_handler(); + register_notifier(DEVICE_NOTIFIER_LCD, display_state_changed); + + ret = sys_set_int(CHARGER_LCD_NODE, CHARGING_LCD_ON); + if (ret < 0) + _E("Can't write %s node.", CHARGER_LCD_NODE); + + ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_DISPLAY, &dbus_interface); + if (ret < 0) + _E("Failed to register dbus object."); +} + +static const struct display_ops display_handler_ops = { + .name = "dislay-handler", + .init = display_handler_init, +}; + +DISPLAY_OPS_REGISTER(&display_handler_ops) diff --git a/plugins/wearable/display/hbm.c b/plugins/wearable/display/hbm.c new file mode 100644 index 0000000..4d0fde5 --- /dev/null +++ b/plugins/wearable/display/hbm.c @@ -0,0 +1,510 @@ +/* + * deviced + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "weaks.h" +#include "display-info.h" +#include "display/util.h" +#include "display/core.h" +#include "display/display-ops.h" +#include "core/common.h" +#include "core/device-notifier.h" +#include "core/config-parser.h" + +#define BOARD_CONF_FILE "/etc/deviced/display.conf" + +#define ON "on" +#define OFF "off" + +#define SIGNAL_HBM_ON "HBMOn" +#define SIGNAL_HBM_OFF "HBMOff" + +#define HBM_LEVEL 120 +#define DEFAULT_BRIGHTNESS_LEVEL 80 + +#define LCD_PATH "sys/class/lcd/" +#define HBM_PATH "/hbm" +#define DEVICE_PATH "/device" +#define PATH_BUFFER_MAX 256 + +static guint timer; +static struct timespec offtime; +static char *hbm_path; + +static void broadcast_hbm_state(char *state) +{ + dbus_handle_emit_dbus_signal(NULL, + DEVICED_PATH_DISPLAY, + DEVICED_INTERFACE_DISPLAY, + state, + NULL); +} + +static void hbm_set_offtime(int timeout) +{ + struct timespec now; + + if (timeout <= 0) { + offtime.tv_sec = 0; + return; + } + + clock_gettime(CLOCK_REALTIME, &now); + offtime.tv_sec = now.tv_sec + timeout; +} + +static gboolean hbm_off_cb(void *data) +{ + int ret; + + timer = 0; + + if (pm_cur_state != S_NORMAL) { + _D("Hbm timeout, but it's not display normal."); + return G_SOURCE_REMOVE; + } + hbm_set_offtime(0); + + ret = sys_set_str(hbm_path, OFF); + if (ret < 0) + _E("Failed to off hbm."); + + ret = vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, + DEFAULT_BRIGHTNESS_LEVEL); + if (ret < 0) { + _E("Failed to set vconf value lcd brightness, %d.", ret); + return G_SOURCE_REMOVE; + } + backlight_ops.set_default_brt(DEFAULT_BRIGHTNESS_LEVEL); + backlight_ops.update(); + broadcast_hbm_state(SIGNAL_HBM_OFF); + + return G_SOURCE_REMOVE; +} + +static void hbm_start_timer(int timeout) +{ + if (timer) { + g_source_remove(timer); + timer = 0; + } + if (!timer) { + timer = g_timeout_add_seconds(timeout, hbm_off_cb, NULL); + } +} + +static void hbm_end_timer(void) +{ + if (timer) { + g_source_remove(timer); + timer = 0; + } +} + +int hbm_get_state(void) +{ + char state[5]; + int ret, hbm; + + if (!hbm_path) + return -ENODEV; + + ret = sys_get_str(hbm_path, state, sizeof(state)); + if (ret < 0) + return ret; + + if (!strncmp(state, ON, strlen(ON))) + hbm = true; + else if (!strncmp(state, OFF, strlen(OFF))) + hbm = false; + else + hbm = -EINVAL; + + return hbm; +} + +int hbm_set_state(int hbm) +{ + if (!hbm_path) + return -ENODEV; + + if (hbm) + broadcast_hbm_state(SIGNAL_HBM_ON); + else + broadcast_hbm_state(SIGNAL_HBM_OFF); + + return sys_set_str(hbm_path, (hbm ? ON : OFF)); +} + +static void hbm_turn_on(void) +{ + if (!hbm_get_state()) + hbm_set_state(true); +} + +static void hbm_turn_off(void) +{ + if (hbm_get_state()) + hbm_set_state(false); +} + +static int hbm_set_state_with_timeout(int hbm, int timeout) +{ + int ret; + + if (hbm && (timeout <= 0)) + return -EINVAL; + + ret = hbm_set_state(hbm); + if (ret < 0) + return ret; + + _D("timeout is %d", timeout); + + if (hbm) { + /* + * hbm is turned off after timeout. + */ + hbm_set_offtime(timeout); + hbm_start_timer(timeout); + } else { + hbm_set_offtime(0); + hbm_end_timer(); + broadcast_hbm_state(SIGNAL_HBM_OFF); + } + + return 0; +} + +void hbm_check_timeout(void) +{ + struct timespec now; + int ret; + + if (timer) { + g_source_remove(timer); + timer = 0; + } + + if (offtime.tv_sec == 0) { + if (hbm_get_state() == true) { + _E("It's invalid state. HBM is turned off."); + hbm_set_state(false); + } + return; + } + + clock_gettime(CLOCK_REALTIME, &now); + _D("now %ld, offtime %ld", now.tv_sec, offtime.tv_sec); + + /* check it's timeout */ + if (now.tv_sec >= offtime.tv_sec) { + hbm_set_offtime(0); + + ret = sys_set_str(hbm_path, OFF); + if (ret < 0) + _E("Failed to off HBM."); + backlight_ops.update(); + broadcast_hbm_state(SIGNAL_HBM_OFF); + } else { + _D("HBM state is restored."); + hbm_set_state(true); + hbm_start_timer(offtime.tv_sec - now.tv_sec); + } +} + +static void hbm_get_level(GVariant *var, void *user_data, GError *err) +{ + int level, brt; + + if (!var) { + _D("Invalid parameter."); + return; + } + + if (!dh_get_param_from_var(var, "(i)", &level)) { + _E("Failed to get message, %s.", g_variant_get_type_string(var)); + goto out; + } + + if (level == HBM_LEVEL && hbm_get_state() == false) { + _I("Lux was high already, HBM enable"); + backlight_ops.get_brightness(&brt); + backlight_ops.transit_brt(brt, PM_MAX_BRIGHTNESS, + display_conf.brightness_change_step); + hbm_set_state(true); + } +out: + g_variant_unref(var); +} + +static gboolean hbm_check_handler(gpointer data) +{ + int ret; + + ret = dbus_handle_method_async_with_reply(COORD_BUS_NAME, + COORD_PATH_AUTOBRIGHTNESS, + COORD_INTERFACE_AUTOBRIGHTNESS, + "GetLevel", + NULL, + NULL, + hbm_get_level, + -1, + NULL); + + if (ret < 0) + _D("Failed to call coord.autobrightness.GetLevel method, %d", ret); + + return G_SOURCE_REMOVE; +} + +static int display_state_changed(void *data) +{ + int state; + int ret; + + state = DATA_VALUE_INT(data); + + if (get_outdoor_setting) + if (get_outdoor_setting()) + return 0; + + switch (state) { + case S_NORMAL: + /* + * outdoor-enhance-mode not supported + * : check & restore hbm always. + * outdoor-enhance-mode supported + * : check & restore hbm when old state is dim only. + */ + if (!get_outdoor_setting || pm_old_state == S_LCDDIM) + hbm_check_timeout(); + + (void) g_timeout_add(300, hbm_check_handler, NULL); + break; + case S_LCDDIM: + case S_LCDOFF: + case S_SLEEP: + if (hbm_get_state() == true) { + ret = hbm_set_state(false); + if (ret < 0) + _E("Failed to off hbm."); + } + hbm_end_timer(); + break; + } + + return 0; +} + +static int display_off_changed(void *data) +{ + int brt; + + if (hbm_get_state() == false) + return 0; + + hbm_turn_off(); + + brt = backlight_ops.get_default_brt(); + if (pm_status_flag & DIMSTAY_FLAG) + _D("skip auto change brightness"); + else + backlight_ops.transit_brt(PM_MAX_BRIGHTNESS, brt, display_conf.brightness_change_step); + + return 0; +} + +static GVariant *dbus_gethbm(GDBusConnection *conn, + const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, + GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) +{ + return g_variant_new("(i)", hbm_get_state()); +} + +static GVariant *dbus_sethbm_timeout(GDBusConnection *conn, + const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, + GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) +{ + int hbm, timeout, ret; + + g_variant_get(param, "(ii)", &hbm, &timeout); + + if (timeout <= 0) { + _E("Timeout can not be setting(%d).", timeout); + ret = -EINVAL; + goto out; + } + + ret = hbm_set_state_with_timeout(hbm, timeout); + + if (ret < 0) + _E("Failed to set HBM (ret=%d, hbm=%d, time=%d).", ret, hbm, timeout); + else + _I("Set hbm (ret=%d, hbm=%d, time=%d).", ret, hbm, timeout); + +out: + return g_variant_new("(i)", ret); +} + +static const dbus_method_s dbus_methods[] = { + { "GetHBM", NULL, "i", dbus_gethbm }, + { "SetHBMTimeout", "ii", "i", dbus_sethbm_timeout }, +}; + +static const dbus_interface_u dbus_interface = { + .oh = NULL, + .name = DEVICED_INTERFACE_DISPLAY, + .methods = dbus_methods, + .nr_methods = ARRAY_SIZE(dbus_methods), +}; + +static int hbm_func(unsigned int cmd, void *arg) +{ + int ret = 0; + int *on; + struct hbmsetstate *hss; + + switch (cmd) { + case HBM_GET_STATE: + ret = hbm_get_state(); + break; + case HBM_SET_STATE: + on = (int *)arg; + ret = hbm_set_state(*on); + break; + case HBM_TURN_ON: + hbm_turn_on(); + break; + case HBM_TURN_OFF: + hbm_turn_off(); + break; + case HBM_SET_TIMEOUT_STATE: + hss = (struct hbmsetstate *)arg; + ret = hbm_set_state_with_timeout(hss->hbm, hss->timeout); + break; + case HBM_TURN_OFF_STATE: + hbm_turn_off(); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static char *check_and_copy_path(char *path) +{ + int fd; + char *buf = NULL; + + fd = open(path, O_RDONLY); + if (fd >= 0) { + buf = strndup(path, strlen(path)); + close(fd); + } else { + _E("Failed to open HBM node."); + } + + return buf; +} + +static char *find_hbm_node() +{ + DIR *d; + struct dirent *dir; + char buf[PATH_BUFFER_MAX]; + char *result = NULL; + + d = opendir(LCD_PATH); + if (!d) + return NULL; + + while ((dir = readdir(d))) { + if (dir->d_name[0] == '.') + continue; + + snprintf(buf, sizeof(buf), "%s%s%s", LCD_PATH, + dir->d_name, HBM_PATH); + + result = check_and_copy_path(buf); + if (result) + break; + + snprintf(buf, sizeof(buf), "%s%s%s%s", LCD_PATH, + dir->d_name, DEVICE_PATH, HBM_PATH); + + result = check_and_copy_path(buf); + if (result) + break; + } + closedir(d); + + return result; +} + +static void hbm_init(void *data) +{ + int ret; + + hbm_path = find_hbm_node(); + + if (!hbm_path) { + _E("Failed to find HBM node."); + return; + } else { + _I("HBM node: %s.", hbm_path); + } + + ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_DISPLAY, &dbus_interface); + if (ret < 0) + _E("Failed to register dbus object."); + + /* register notifier */ + register_notifier(DEVICE_NOTIFIER_LCD, display_state_changed); + register_notifier(DEVICE_NOTIFIER_LCD_OFF, display_off_changed); +} + +static void hbm_exit(void *data) +{ + /* unregister notifier */ + unregister_notifier(DEVICE_NOTIFIER_LCD_OFF, display_off_changed); + unregister_notifier(DEVICE_NOTIFIER_LCD, display_state_changed); + + /* + * set default brightness + * if display logic is stopped in hbm state. + */ + if (hbm_get_state() == true) { + hbm_set_offtime(0); + _I("set brightness to default value!"); + } +} + +static const struct display_ops display_hbm_ops = { + .name = "hbm", + .init = hbm_init, + .exit = hbm_exit, + .func = hbm_func, +}; + +DISPLAY_OPS_REGISTER(&display_hbm_ops) + diff --git a/plugins/wearable/display/hbm.h b/plugins/wearable/display/hbm.h new file mode 100644 index 0000000..d555152 --- /dev/null +++ b/plugins/wearable/display/hbm.h @@ -0,0 +1,50 @@ +/* + * deviced + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @file hbm.h + * @brief High Brightness Mode header file + */ +#ifndef __HBM_H__ +#define __HBM_H__ + +/* + * @brief Configuration structure + */ +struct hbm_config { + int on; + int off; + int on_count; + int off_count; +}; + +int hbm_get_state(void); +int hbm_set_state(int hbm); + +/* + * Global variables + * hbm_conf : configuration of hbm + */ +extern struct hbm_config hbm_conf; + +/** + * @} + */ + +#endif diff --git a/plugins/wearable/display/lbm.c b/plugins/wearable/display/lbm.c new file mode 100644 index 0000000..c098efd --- /dev/null +++ b/plugins/wearable/display/lbm.c @@ -0,0 +1,376 @@ +/* + * deviced + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "lbm.h" +#include "display-info.h" +#include "display/util.h" +#include "display/core.h" +#include "display/display-ops.h" +#include "core/common.h" +#include "core/config-parser.h" +#include "core/device-notifier.h" + +#define DISPLAY_CONF_FILE "/etc/deviced/display.conf" + +#define SIGNAL_LBM_ON "LBMOn" +#define SIGNAL_LBM_OFF "LBMOff" + +#define LCD_PHASED_DELAY 10000 /* microsecond */ + +#define LBM_TRANSIT_STEP 20 + +struct lbm_config lbm_conf = { + .support = 0, + .down_level = 0, + .brt_table_size = 0, + .brt_table = NULL, + .aod_brightness_level = 0, +}; + +static bool lbm_state; +static int lbm_setting_mode; +static int system_brightness; +static struct display_device *display_dev; + +static void broadcast_lbm_state(int state) +{ + char *str; + + if (state == 1) + str = SIGNAL_LBM_ON; + else + str = SIGNAL_LBM_OFF; + + dbus_handle_emit_dbus_signal(NULL, + DEVICED_PATH_DISPLAY, + DEVICED_INTERFACE_DISPLAY, + str, + NULL); +} + +static int get_level_by_brt(int brt) +{ + int iter; + for (iter = 0; iter < lbm_conf.brt_table_size; iter++) { + if (lbm_conf.brt_table[iter] == brt) + return iter; + } + return -EINVAL; +} + +static int lbm_down_brt(int brt) +{ + int level; + int down_level; + + if (lbm_conf.down_level == 0) { + _I("LBM down level setting is 0."); + return brt; + } + + if (lbm_conf.brt_table == NULL || lbm_setting_mode == 0) { + _I("LBM setting mode is %d.", lbm_setting_mode); + return brt; + } + + level = get_level_by_brt(brt); + down_level = level - lbm_conf.down_level; + + if (down_level < 0) + down_level = 0; + + return lbm_conf.brt_table[down_level]; +} + +int lbm_get_state(void) +{ + if (!lbm_conf.support) + return -ENODEV; + + return lbm_state; +} + +static int lbm_get_brightness(int *val) +{ + if (system_brightness == 0) + _E("Failed to get brightness."); + + *val = system_brightness; + + return 0; +} + +static int lbm_set_brightness(int val) +{ + int brt = 0; + + if (!display_dev || !display_dev->set_brightness) { + _E("There is no display device."); + return -ENOENT; + } + + if (pm_status_flag & DIM_MASK) + val = 0; + else + brt = lbm_down_brt(val); + + system_brightness = val; + + _I("Set brightness(LBM on) system=%d, real=%d.", val, brt); + device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val); + + return display_dev->set_brightness(brt); +} + +static void lbm_change_brightness(int start, int end, int step) +{ + int diff, val; + int ret = -1; + int prev; + + if (display_dimstay_check()) + return; + + ret = backlight_ops.get_brightness(&prev); + + if (ret < 0) { + _E("Failed to get brightness, %d.", ret); + return; + } + + if (prev == end) + return; + + if (pm_status_flag & DIM_MASK) + end = 0; + + _I("Start %d, end %d, step %d.", start, end, step); + + if (display_dev && display_dev->set_multi_brightness) { + diff = lbm_down_brt(end); + + ret = display_dev->set_multi_brightness(diff, step, LCD_PHASED_DELAY); + if (ret < 0) + _E("Failed to set_multi_brightness, %d.", ret); + + backlight_ops.set_brightness(end); + + return; + } + + diff = end - start; + + if (abs(diff) < step) + val = (diff > 0 ? 1 : -1); + else + val = (int)ceil((double)diff / step); + + while (start != end) { + if (val == 0) + break; + + start += val; + if ((val > 0 && start > end) || + (val < 0 && start < end)) + start = end; + + usleep(LCD_PHASED_DELAY); + backlight_ops.set_brightness(start); + } +} + +int lbm_set_state(int lbm) +{ + int brt; + _I("lbm_set_state"); + + if (lbm == lbm_state) { + _W("already lbm %s", (lbm_state ? "on" : "off")); + return 0; + } + + if (!lbm || lbm_setting_mode) { + lbm_state = lbm; + broadcast_lbm_state(lbm_state); + } + + brt = backlight_ops.get_default_brt(); + _I("Default brightness: %d", brt); + if (lbm && lbm_setting_mode) { + _I("Lowering Brightness."); + backlight_ops.transit_brt(brt, lbm_down_brt(brt), LBM_TRANSIT_STEP); + backlight_ops.get_brightness(&system_brightness); + backlight_ops.set_brightness = lbm_set_brightness; + backlight_ops.get_brightness = lbm_get_brightness; + backlight_ops.transit_brt = lbm_change_brightness; + } else { + system_brightness = 0; + backlight_ops.restore_brightness_func(); + backlight_ops.transit_brt(lbm_down_brt(brt), brt, display_conf.brightness_change_step); + } + + backlight_ops.set_brightness(brt); + + return 0; +} + +static void lbm_table_load(char *value, struct lbm_config *c) +{ + char *p, *saveptr; + int level_count = 1; + int i; + + if (value == '\0') + return; + + for (i = 0; *(value + i) != '\0'; i++) { + if (*(value + i) == ',') + level_count++; + } + + c->brt_table = malloc(sizeof(int) * level_count); + if (!c->brt_table) { + _E("Failed to allocate memory."); + return; + } + c->brt_table_size = level_count; + + i = 0; + p = strtok_r(value, ",", &saveptr); + if (p) + c->brt_table[i++] = atoi(p); + + while (p != NULL) { + p = strtok_r(NULL, ",", &saveptr); + if (p) + c->brt_table[i++] = atoi(p); + } +} + +static int lbm_load_config(struct parse_result *result, void *user_data) +{ + struct lbm_config *c = user_data; + + _D("%s,%s,%s.", result->section, result->name, result->value); + + if (!c) + return -EINVAL; + + if (!MATCH(result->section, "Display")) + return 0; + + if (MATCH(result->name, "LBMsupport")) { + c->support = (MATCH(result->value, "yes") ? 1 : 0); + _D("lbm support is %d", c->support); + } else if (MATCH(result->name, "Level")) { + SET_CONF(c->down_level, atoi(result->value)); + _D("lbm down level is %d", c->down_level); + } else if (MATCH(result->name, "BrtTable")) { + lbm_table_load(result->value, c); + _D("LBM table loaded."); + } + + return 0; +} + +static void lbm_mode_changed(keynode_t *key_nodes, void *data) +{ + int mode = vconf_keynode_get_bool(key_nodes); + + _I("LBM setting value is %s.", mode ? "enable" : "disable"); + + lbm_setting_mode = mode; + + if (lbm_get_state()) + lbm_set_state(false); +} + +static int display_off_changed(void *data) +{ + int brt; + + backlight_ops.get_brightness(&brt); + backlight_ops.restore_brightness_func(); + backlight_ops.set_brightness(brt); + + lbm_state = 0; + + return 0; +} + +static GVariant *dbus_getlbm(GDBusConnection *conn, + const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, + GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) +{ + int lbm; + + lbm = lbm_get_state(); + if (lbm < 0) + _E("Failed to get low brightness mode %d.", lbm); + else + _D("Get low brightness mode %d.", lbm); + + return g_variant_new("(i)", lbm); +} + +static const dbus_method_s dbus_methods[] = { + { "GetLBM", NULL, "i", dbus_getlbm }, +}; + +static const dbus_interface_u dbus_interface = { + .oh = NULL, + .name = DEVICED_INTERFACE_DISPLAY, + .methods = dbus_methods, + .nr_methods = ARRAY_SIZE(dbus_methods), +}; +static void lbm_init(void *data) +{ + int ret; + + /* load configutation */ + ret = config_parse(DISPLAY_CONF_FILE, lbm_load_config, &lbm_conf); + if (ret < 0) + _W("Failed to load %s, %d. Use default value.", DISPLAY_CONF_FILE, ret); + + ret = vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_AUTOMATIC_LOW_BRIGHTNESS, &lbm_setting_mode); + if (ret < 0) + _E("Failed to get VCONFKEY_SETAPPL_ACCESSIBILITY_AUTOMATIC_LOW_BRIGHTNESS, %d.", ret); + + vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_AUTOMATIC_LOW_BRIGHTNESS, lbm_mode_changed, NULL); + + ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_DISPLAY, &dbus_interface); + if (ret < 0) + _E("Failed to init dbus method, %d.", ret); + + display_dev = display_dev_get(); + + _I("LBM setting value is %d.", lbm_setting_mode); + + /* register notifier */ + register_notifier(DEVICE_NOTIFIER_LCD_OFF_COMPLETE, display_off_changed); +} + +static const struct display_ops display_lbm_ops = { + .name = "lbm", + .init = lbm_init, +}; + +DISPLAY_OPS_REGISTER(&display_lbm_ops) diff --git a/plugins/wearable/display/lbm.h b/plugins/wearable/display/lbm.h new file mode 100644 index 0000000..5b1e319 --- /dev/null +++ b/plugins/wearable/display/lbm.h @@ -0,0 +1,50 @@ +/* + * deviced + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file lbm.h + * @brief Low Brightness Mode header file + */ +#ifndef __LBM_H__ +#define __LBM_H__ + +/* + * @brief Configuration structure + */ +struct lbm_config { + int support; + int down_level; + int brt_table_size; + int *brt_table; + int aod_brightness_level; +}; + +/* + * Global variables + * lbm_conf : configuration of lbm + */ +struct lbm_config lbm_conf; + +int lbm_get_state(void); +int lbm_set_state(int lbm); + +/** + * @} + */ + +#endif diff --git a/plugins/wearable/display/weaks.h b/plugins/wearable/display/weaks.h new file mode 100644 index 0000000..e8c764e --- /dev/null +++ b/plugins/wearable/display/weaks.h @@ -0,0 +1,29 @@ +/* + * deviced + * + * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __DISPLAY_WEAKS_H__ +#define __DISPLAY_WEAKS_H__ + +#include "core/common.h" +#include "display/core.h" + +bool __WEAK__ get_outdoor_setting(void); + +#endif +