battery-monitor: initial module 56/214356/13
authorsanghyeok.oh <sanghyeok.oh@samsung.com>
Fri, 20 Sep 2019 12:10:55 +0000 (21:10 +0900)
committersanghyeok oh <sanghyeok.oh@samsung.com>
Mon, 9 Dec 2019 11:35:38 +0000 (11:35 +0000)
Change-Id: Ib353d1baf71816e7cdfe89e9b879759d05504f9f
Signed-off-by: sanghyeok.oh <sanghyeok.oh@samsung.com>
CMakeLists.txt
conf/org.tizen.system.deviced.conf
plugins/wearable/display/CMakeLists.txt
plugins/wearable/display/core.c
plugins/wearable/display/device-interface.c
src/battery-monitor/CMakeLists.txt [new file with mode: 0644]
src/battery-monitor/battery-monitor.c [new file with mode: 0644]
src/battery-monitor/battery-monitor.h [new file with mode: 0644]

index d686a33..3721a6a 100644 (file)
@@ -300,6 +300,7 @@ IF(TIZEN_FEATURE_USBHOST_TEST STREQUAL on)
                        DESTINATION lib/systemd/system)
 ENDIF()
 
+ADD_SUBDIRECTORY(src/battery-monitor)
 ADD_SUBDIRECTORY(src/shared)
 ADD_SUBDIRECTORY(src/libdeviced)
 ADD_SUBDIRECTORY(src/devicectl)
index 5ef074e..aa4a653 100644 (file)
             send_interface="org.tizen.system.deviced.Battery"/>
     </policy>
 
+    <policy user="service_fw">
+      <allow send_destination="org.tizen.system.deviced" send_interface="org.tizen.system.deviced.BatteryMonitor" send_member="GetBMData"/>
+    </policy>
+
     <policy user="system_fw">
       <allow send_destination="org.tizen.system.deviced" send_interface="org.tizen.system.deviced.Battery" send_member="power_supply"/>
       <allow send_destination="org.tizen.system.deviced" send_interface="org.tizen.system.deviced.ExtCon"/>
index 00290fc..0a4f329 100644 (file)
@@ -6,7 +6,7 @@ SET(SRCS ${ALL_SRCS})
 ADD_SOURCE(${CMAKE_SOURCE_DIR}/src/display COMMON_SRCS)
 SET(SRCS ${SRCS} ${COMMON_SRCS})
 
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/display)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/display ${CMAKE_SOURCE_DIR}/src/battery-monitor)
 
 INCLUDE(FindPkgConfig)
 pkg_check_modules(libpkgs REQUIRED
@@ -26,7 +26,7 @@ ENDFOREACH(flag)
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_LIB_CFLAGS}")
 
 ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${libpkgs_LDFLAGS} shared)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${libpkgs_LDFLAGS} shared batterymonitor)
 SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "")
 SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES OUTPUT_NAME wearable-display)
 INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
index e328df8..41a2ce6 100644 (file)
@@ -59,6 +59,7 @@
 #include "dd-display.h"
 #include "display/display-dpms.h"
 #include "display-info.h"
+#include "battery-monitor.h"
 
 #define DISPLAY_CONF_FILE    "/etc/deviced/display.conf"
 
@@ -2050,6 +2051,9 @@ static int default_action(int timeout)
                    states[pm_cur_state].name, last_timeout, diff);
        }
 
+       /* update status for batter monitor */
+       update_bds_record(pm_cur_state);
+
        switch (pm_cur_state) {
        case S_NORMAL:
                /*
index d1b536f..9b5d656 100644 (file)
@@ -42,6 +42,7 @@
 #include "core.h"
 #include "device-node.h"
 #include "display/display-dpms.h"
+#include "battery-monitor.h"
 
 #define SET_SUSPEND_TIME               0.5
 
@@ -599,6 +600,7 @@ static int set_brightness(int val)
         * Thus real brightness need to be calculated */
        val = val * max / 100;
 
+       update_bds_brightness_record(val);
        _I("set brightness %d (default:%d)", val, default_brightness);
        device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
 
diff --git a/src/battery-monitor/CMakeLists.txt b/src/battery-monitor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9937f06
--- /dev/null
@@ -0,0 +1,18 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+FILE(GLOB SHARED_SRCS "*.c")
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(libshared REQUIRED
+       glib-2.0
+       gio-2.0
+       gio-unix-2.0
+       dlog)
+
+FOREACH(flag ${libshared_CFLAGS})
+       SET(SHARED_LIB_CFLAGS "${SHARED_LIB_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+ADD_LIBRARY(batterymonitor STATIC ${SHARED_SRCS})
+TARGET_LINK_LIBRARIES(batterymonitor ${libshared_LDFLAGS} "-ldl")
+SET_TARGET_PROPERTIES(batterymonitor PROPERTIES COMPILE_FLAGS "-fPIC")
diff --git a/src/battery-monitor/battery-monitor.c b/src/battery-monitor/battery-monitor.c
new file mode 100644 (file)
index 0000000..9ceff29
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2019 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 <sys/time.h>
+#include <unistd.h>
+#include <libsyscommon/dbus-system.h>
+
+#include "battery-monitor.h"
+
+#include "core/log.h"
+#include "core/devices.h"
+#include "core/common.h"
+#include "display/core.h"
+
+#define DBUS_DEVICED "org.tizen.system.deviced"
+#define DBUS_DEVICED_BM_PATH "/Org/Tizen/System/DeviceD/BatteryMonitor"
+#define DBUS_DEVICED_BM_IFACE "org.tizen.system.deviced.BatteryMonitor"
+#define DBUS_DEVICED_BM_MEMBER "GetBMData"
+
+/* battery-monitor interface */
+_battery_monitor_ops bm_ops;
+
+typedef enum {
+       B_LOW = 0,
+       B_MED,
+       B_HIGH,
+       B_UNKNOWN,
+} brightness_level;
+
+static char *prev_appid;
+static char *cur_appid;
+
+static enum state_t prev_lcd_state = S_LCDOFF;
+
+/*
+ * hash map for app_time_map_st1
+ * key(appid) : (char *)
+ * val(elapsed time/ms) : (unsigned int *)
+ */
+GHashTable *ht_apptime;
+
+static bool bm_started = false;
+static time_t bm_time_start;
+static time_t bm_time_end;
+
+/* elapsed time per brightness level(milliseconds) */
+static unsigned int brightness_time[B_UNKNOWN];
+static brightness_level prev_brightness_level = B_UNKNOWN;
+
+#define timeval_to_ms(time) ((time.tv_sec * 1000) + (time.tv_usec / 1000))
+#define timeval_diff_ms(tend, tstart) (timeval_to_ms(tend) - timeval_to_ms(tstart))
+
+/* monitoring time */
+#define bds_init_monitoring_time() (bm_time_start = bm_time_end = 0)
+#define bds_set_start_time() (time(&bm_time_start))
+#define bds_set_end_time() (time(&bm_time_end))
+
+static struct timeval bds_time_prev;
+#define bds_timer_init() (bds_time_prev.tv_sec = bds_time_prev.tv_usec = 0)
+#define bds_timer_start() (gettimeofday(&bds_time_prev, NULL))
+
+/* dbus signal subscription id : AppStatusChange */
+guint dbus_sub_id;
+
+static void _init_bds_brightness_time()
+{
+       int i;
+
+       for (i = 0; i < B_UNKNOWN; ++i)
+               brightness_time[i] = 0;
+}
+
+static void _update_bds_brightness_time(unsigned long elapsed_ms)
+{
+       if (prev_brightness_level >= B_UNKNOWN)
+               return;
+
+       _I("update brightness time %lu elapsed", elapsed_ms);
+
+       brightness_time[prev_brightness_level] += elapsed_ms;
+}
+
+static unsigned long bds_timer_get_elapsed_ms()
+{
+       struct timeval cur_time;
+       unsigned long ret;
+
+       if (bds_time_prev.tv_sec == 0) {
+               bds_timer_start();
+               return 0;
+       }
+
+       gettimeofday(&cur_time, NULL);
+
+       ret = timeval_diff_ms(cur_time, bds_time_prev);
+
+       /* update prev bds time */
+       bds_time_prev.tv_sec = cur_time.tv_sec;
+       bds_time_prev.tv_usec = cur_time.tv_usec;
+
+       return ret;
+}
+
+static void update_apptime(const char *appid, unsigned long elapsed)
+{
+       unsigned int *ptime;
+
+       if (!appid) {
+               _E("wrong input %s %lu", appid, elapsed);
+               return ;
+       }
+       if (elapsed == 0) {
+               _D("elaped time is 0. No update");
+               return ;
+       }
+       /* display core is initialized at first */
+       if (!ht_apptime) {
+               _D("battery-monitor moulde is not initialized");
+               return ;
+       }
+
+       _I("update apptime. %lu elapsed", elapsed);
+
+       ptime = g_hash_table_lookup(ht_apptime, appid);
+       if (ptime) {
+               *ptime += elapsed;
+               return ;
+       }
+
+       ptime = (unsigned int*)malloc(sizeof(unsigned int));
+       if (!ptime) {
+               _E("failed to alloc memory");
+               return ;
+       }
+
+       *ptime = elapsed;
+
+       g_hash_table_insert(ht_apptime, g_strdup(appid), ptime);
+}
+
+static void update_appid(void)
+{
+       g_free(prev_appid);
+       prev_appid = g_strdup(cur_appid);
+}
+
+int update_bds_record(enum state_t cur_lcd_state)
+{
+       unsigned long elapsed = 0;
+
+       if (!bm_started) {
+               prev_lcd_state = cur_lcd_state;
+               update_appid();
+
+               bds_set_start_time();
+               bds_timer_start();
+               bm_started = true;
+
+               _I("battery monitor started");
+
+               return 0;
+       }
+
+       elapsed = bds_timer_get_elapsed_ms();
+
+       /* no effect : prev state(lcd off) -> on or off */
+       if (prev_lcd_state >= S_LCDOFF) {
+               prev_lcd_state = cur_lcd_state;
+               _D("LCD OFF State. prev(%d)->cur(%d)", prev_lcd_state, cur_lcd_state);
+
+               update_appid();
+               _D("foreground app has changed %s->%s", prev_appid, cur_appid);
+
+               return 0;
+       }
+
+       if (prev_appid)
+               update_apptime(prev_appid, elapsed);
+
+       _update_bds_brightness_time(elapsed);
+
+       /* update previous state */
+       prev_lcd_state = cur_lcd_state;
+
+       update_appid();
+
+       return 0;
+}
+
+static brightness_level get_brightness_level(unsigned int val)
+{
+       if (val > 100)
+               return B_UNKNOWN;
+
+       val = val / 33;
+       if (val > 2)
+               val = 2;
+
+       return (brightness_level)val;
+}
+
+int update_bds_brightness_record(unsigned int val)
+{
+       brightness_level level = get_brightness_level(val);
+
+       if (level == B_UNKNOWN)
+               return -1;
+
+       _I("update brightness %u %d", val, (int)level);
+
+       update_bds_record(prev_lcd_state);
+
+       /* update previous state */
+       prev_brightness_level = level;
+
+       return 0;
+}
+
+static void _set_current_appid(const char *appid, int foreground)
+{
+       if (!appid)
+               return;
+
+       /* appid is not changed */
+       if (cur_appid && strcmp(cur_appid, appid) == 0)
+               return;
+
+       if (!foreground) {
+               /* if bg notification is different with cur_appid, ignore */
+               if (cur_appid && strcmp(cur_appid, appid) != 0) {
+                       _D("different appid has changed to bg. ignore");
+                       return;
+               }
+
+               /* if bg, set null */
+               appid = NULL;
+       }
+
+       g_free(cur_appid);
+       cur_appid = g_strdup(appid);
+
+       update_bds_record(prev_lcd_state);
+}
+
+static void _builder_add_atm_data(GVariantBuilder *atm_builder)
+{
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_hash_table_iter_init (&iter, ht_apptime);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               g_variant_builder_add(atm_builder, "(su)", (const char *)key, (*(unsigned int*)value));
+               _D("value added %s, %u", (const char *)key, (*(unsigned int*)value));
+       }
+       g_hash_table_remove_all(ht_apptime);
+}
+
+static GVariant *_convert_bds_data_to_gvariant(void)
+{
+       GVariant *out_variant = NULL;
+       GVariantBuilder *bds_builder = NULL;
+       GVariantBuilder *atm_builder = NULL;
+       gint64 t_start;
+       gint64 t_end;
+
+       t_start = bm_time_start;
+       t_end = bm_time_end;
+
+       /* convert bm_display_st data to gvariant */
+       bds_builder = g_variant_builder_new(G_VARIANT_TYPE("a(uuuxxa(su))"));
+
+       for (int i = 0 ; i < 1; ++i) {
+               /* convert app_time_map_st1 to gvariant array */
+               atm_builder = g_variant_builder_new(G_VARIANT_TYPE("a(su)"));
+               _builder_add_atm_data(atm_builder);
+
+               g_variant_builder_add(bds_builder, "(uuuxxa(su))",
+                                               brightness_time[B_HIGH],
+                                               brightness_time[B_LOW],
+                                               brightness_time[B_MED],
+                                               t_start,
+                                               t_end,
+                                               atm_builder);
+               g_variant_builder_unref(atm_builder);
+       }
+
+       out_variant = g_variant_new("(a(uuuxxa(su)))", bds_builder);
+       g_variant_builder_unref(bds_builder);
+
+       _init_bds_brightness_time();
+
+       return out_variant;
+}
+
+static void _init_bm_ops(void)
+{
+       bm_ops.update_bds_record = update_bds_record;
+}
+
+static GVariant *dbus_get_bm_data(GDBusConnection *conn,
+                               const gchar *sender,
+                               const gchar *path,
+                               const gchar *iface,
+                               const gchar *name,
+                               GVariant *param,
+                               GDBusMethodInvocation *invocation,
+                               gpointer user_data)
+{
+       GVariant *reply;
+       gchar *ret;
+
+       update_bds_record(prev_lcd_state);
+
+       bds_set_end_time();
+       reply = _convert_bds_data_to_gvariant();
+       bds_set_start_time();
+
+       ret = g_variant_print(reply, true);
+       _I("Reply battery monitor data:%s:%s", g_variant_get_type_string(reply), ret);
+       g_free(ret);
+
+       return reply;
+}
+
+/* dbus signal handler : AppStatusChange */
+static void _dbus_cb_AppStatusChange(GDBusConnection  *conn,
+                               const gchar *sender,
+                               const gchar *path,
+                               const gchar *iface,
+                               const gchar *name,
+                               GVariant *param,
+                               gpointer data)
+{
+       int pid;
+       char *appid;
+       char *status;
+
+       /* (issss) : pid, appid, pkgid, status, type */
+       g_variant_get(param, "(issss)", &pid, &appid, NULL, &status, NULL);
+
+       _I("pid:%d, appid:%s, status:%s", pid, appid, status);
+
+       _set_current_appid(appid, strcmp(status, "fg") == 0);
+
+       g_free(appid);
+       g_free(status);
+}
+
+static const dbus_method_s bm_dbus_methods[] = {
+       {"GetBMData", NULL, "a(uuuxxa(su))", dbus_get_bm_data},
+};
+
+static const dbus_interface_u bm_dbus_interface = {
+       .oh = NULL,
+       .name = DBUS_DEVICED_BM_IFACE,
+       .methods = bm_dbus_methods,
+       .nr_methods = ARRAY_SIZE(bm_dbus_methods),
+};
+
+static void bm_data_init(void)
+{
+       if (ht_apptime) {
+               g_hash_table_destroy(ht_apptime);
+               ht_apptime = NULL;
+       }
+
+       bm_started = false;
+
+       g_free(cur_appid);
+       cur_appid = NULL;
+
+       g_free(prev_appid);
+       prev_appid = NULL;
+
+       bds_timer_init();
+       bds_init_monitoring_time();
+       _init_bds_brightness_time();
+}
+
+static int bm_probe(void *data)
+{
+       _init_bm_ops();
+
+       return 0;
+}
+
+static void _ht_key_destroy(gpointer data)
+{
+       char *pdata = (char *)data;
+
+       if (!pdata)
+               return;
+
+       g_free(pdata);
+}
+
+static void _ht_val_destroy(gpointer data)
+{
+       unsigned int *pdata = (unsigned int *)data;
+
+       if (!pdata)
+               return;
+
+       free(pdata);
+}
+
+static void bm_init(void *data)
+{
+       int ret;
+
+       ht_apptime = g_hash_table_new_full(g_str_hash, g_str_equal, _ht_key_destroy, _ht_val_destroy);
+       if (!ht_apptime)
+               _E("Failed to init hash table");
+
+       ret = dbus_handle_add_dbus_object(NULL, DBUS_DEVICED_BM_PATH, &bm_dbus_interface);
+       if (ret < 0)
+               _E("Failed to init dbus method: %d", ret);
+
+       dbus_sub_id = subscribe_dbus_signal(NULL,
+                               "/Org/Tizen/Aul/AppStatus",
+                               "org.tizen.aul.AppStatus",
+                               "AppStatusChange",
+                               _dbus_cb_AppStatusChange,
+                               NULL, NULL);
+       if (dbus_sub_id <= 0)
+               _E("Failed to register signal handler: %d", dbus_sub_id);
+}
+
+static void bm_exit(void *data)
+{
+       int ret;
+
+       ret = dbus_handle_unregister_dbus_object(NULL, DBUS_DEVICED_BM_PATH);
+       if (ret < 0)
+               _E("Failed to unregister dbus object: %d", ret);
+
+       if (dbus_sub_id > 0)
+               unsubscribe_dbus_signal(NULL, dbus_sub_id);
+       dbus_sub_id = 0;
+
+       bm_data_init();
+}
+
+static const struct device_ops battery_monitor_ops = {
+       DECLARE_NAME_LEN("battery-monitor"),
+       .probe  = bm_probe,
+       .init   = bm_init,
+       .exit   = bm_exit,
+};
+
+DEVICE_OPS_REGISTER(&battery_monitor_ops)
diff --git a/src/battery-monitor/battery-monitor.h b/src/battery-monitor/battery-monitor.h
new file mode 100644 (file)
index 0000000..25dde1e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2019 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 __BATTERY_MONITOR_H__
+#define __BATTERY_MONITOR_H__
+
+#include "display/core.h"
+
+typedef struct {
+       int (*update_bds_record)(enum state_t lcd_state);
+       int (*update_bds_brightness_record)(unsigned int val);
+} _battery_monitor_ops;
+
+extern _battery_monitor_ops bm_ops;
+
+int update_bds_record(enum state_t lcd_state);
+int update_bds_brightness_record(unsigned int val);
+
+#endif /* __BATTERY_MONITOR_H__ */
\ No newline at end of file