heart : upgrade HEART-battery 92/100092/10 accepted/tizen/3.0/ivi/20161205.235125 accepted/tizen/3.0/mobile/20161205.235030 accepted/tizen/3.0/tv/20161205.235048 accepted/tizen/3.0/wearable/20161205.235106 submit/tizen_3.0/20161205.073831
authorKichan Kwon <k_c.kwon@samsung.com>
Fri, 25 Nov 2016 05:50:35 +0000 (14:50 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Mon, 5 Dec 2016 07:12:31 +0000 (16:12 +0900)
1) Stability
  - Use enum for charger status instead of integer
  - Fix memory leak
  - Asynchronous (level)DB updating

2) New function
  - Discharge rate : HIGH(1.2x~), LOW(~0.8x), compare with predicted rate
  - New logic for battery remaining time estimation
    - Calculate SOE(State Of Energy) decreasing rate
    - SOE is considered to the integral of OCP(Open-Circuit Potential)
    - To use new logic, vendor have to support battery capacity and OCV coefficients

Change-Id: Ic80073028d8fde16980a53d8cb550023b56cb8b8
Signed-off-by: Kichan Kwon <k_c.kwon@samsung.com>
src/common/heart-common.h
src/heart/heart-battery.c
src/heart/heart.conf

index b915126..da6f06b 100644 (file)
@@ -39,6 +39,20 @@ enum heart_data_period {
        DATA_1WEEK,
 };
 
+enum charger_status_type {
+       DISCHARGING = 0,
+       CHARGING = 1,
+       MAX_CHARGER_STATE = 2,
+};
+
+enum discharge_rate_level_type {
+       BATTERY_DISCHARGE_NONE = -1,
+       BATTERY_DISCHARGE_LOW = 0,
+       BATTERY_DISCHARGE_AVG = 1,
+       BATTERY_DISCHARGE_HIGH = 2,
+       BATTERY_DISCHARGE_MAX = 3,
+};
+
 struct heart_cpu_data {
        char appid[MAX_APPID_LENGTH];
        char pkgid[MAX_PKGNAME_LENGTH];
@@ -69,10 +83,14 @@ struct heart_battery_capacity {
        int diff_capacity;
        long used_time;
        long charging_time;
-       int charger_status;
+       enum charger_status_type charger_status;
        int reset_mark;
 };
-/* battery capacity history*/
+
+/* battery */
+int heart_battery_get_capacity(void);
+enum charger_status_type heart_battery_get_charger_status(void);
+enum discharge_rate_level_type heart_battery_get_discharge_rate_level(void);
 int heart_battery_get_capacity_history_latest(GArray *arrays, int charge, int max_size);
 int heart_battery_get_capacity_history(GArray *arrays, enum heart_data_period period);
 
index 2bc703e..6b7c388 100644 (file)
 #include "heart-common.h"
 #include "config-parser.h"
 #include "trace.h"
+#include "vconf.h"
 #include "module.h"
 #include "macro.h"
+#include "util.h"
+#include "file-helper.h"
 
 #define TIZEN_SYSTEM_APPID                     "org.tizen.system"
 #define TIZEN_SYSTEM_BATTERY_APPID             "org.tizen.system.battery.capacity"
@@ -66,6 +69,8 @@
 #define BATTERY_USAGE_LEARNING                 -1
 #define CUMUL_WEIGHT                           (0.8)
 #define TREND_WEIGHT                           (1 - CUMUL_WEIGHT)
+#define DISCHARGE_BASE_RATE                    (0.2)
+
 /*
  * BATTERY_PREDICTION_LATEST_COUNT must be >= BATTERY_PREDICTION_DATA_MIN
  */
 #define BATTERY_LEVEL_USAGE                     "BATTERY_LEVEL_USAGE"
 #define BATTERY_PREDICTION                      "BATTERY_PREDICTION"
 
+#define INDEX_WINDOW_SIZE              10  /*data storing index*/
+#define BATTERY_LEVEL_GAP              5  /*previous 5 battery data*/
+#define LONG_TIME_WEIGHT               (0.7) /*weightage given for longer time discharge*/
+#define SHORT_TIME_WEIGHT              (1-LONG_TIME_WEIGHT) /*weightage given for short time discharge*/
+#define MIN_TIME_FOR_LVL_CHANGE                50
+
+/*
+ * Below 6 values are the co-efficient of the polynomial. These are devired from
+ * OCV and  and battery percentage level based on experiment
+ */
+#define OCV_SOC_POLY_COEF_1                    (3402.664)
+#define OCV_SOC_POLY_COEF_2                    (42.031)
+#define OCV_SOC_POLY_COEF_3                    (-1.76745)
+#define OCV_SOC_POLY_COEF_4                    (0.034798)
+#define OCV_SOC_POLY_COEF_5                    (-0.00030516)
+#define OCV_SOC_POLY_COEF_6                    (0.0000010116)
+#define UPS_FACTOR                             (2.88)
+#define DOUBLE_ZERO                            (0.000000)
+#define FULL_CAPACITY                  100
+/* BATTERY_C_RATE is defined as the rate of which battery capacity is changing
+ * If total battery capacity is XmAh, then in one second battery capacity change
+ * will be considered as 90
+ */
+#define BATTERY_C_RATE                 90
+#define SEC_TO_MIN(x) ((x)/60)
+#define CAL_MIN(x, y) ((x < y) ? x : y)
+#define BATTERY_WINDOW_INDEX(x)                (((x) +  INDEX_WINDOW_SIZE) % INDEX_WINDOW_SIZE)
+#define HEART_BATTERY_DATA_FILE                HEART_FILE_PATH"/.battery_data.dat"
+#define VCONFKEY_HEART_BATTERY_DEVICE_MODE                     "db/setting/psmode"
+
 enum {
        TA     = 0,     /* prediction based on total data average */
        PCB    = 1,     /* prediction with physiological behaviors */
@@ -99,12 +134,6 @@ enum {
        POWER_MODE_MAX     = 3,
 };
 
-enum charging_goal {
-       DISCHARGING = 0,
-       CHARGING = 1,
-       MAX_CHARGER_STATE = 2,
-};
-
 enum {
        BATTERY_LEVEL_LOW = 0, /* 15 ~ 0 */
        BATTERY_LEVEL_MID = 1, /* 49 ~ 16 */
@@ -139,15 +168,35 @@ struct battery_prediction {
 
 struct battery_status {
        /* current battery status */
-       int curr_charger_status;
+       enum charger_status_type curr_charger_status;
        int curr_capacity;
 
+       enum discharge_rate_level_type discharge_rate_level;
        /* current runtime statistics */
        long curr_run_time_sec[MAX_CHARGER_STATE]; /* seconds since reset */
        long curr_cap_counter[MAX_CHARGER_STATE]; /* capacity level changes */
 
+       long last_wall_time[INDEX_WINDOW_SIZE];  /* previous battery level discharge time */
+       /* previous battery level change time in charging mode */
+       long last_wall_time_chg;
+       /* charging data index*/
+       int index_chg;
+       /* store last 5 battery level change time diff */
+       int last_wall_time_chg_diff[BATTERY_LEVEL_GAP];
+        /* indicates whether do we have enough data to estimate the battery time */
+       int data_available;
+       int curr_index;  /* store current index value */
+       int last_capacity;  /* last battery capacity value */
+       int last_capacity_chg; /* last battery capacity value in charge mode */
+       int remaining_time; /* previous remaining time */
+       int remaining_time_chg; /* previous remaining time in charging mode */
+       int remaining_time_ups; /* previous remaining time in UPS */
+       double last_volt_intg[INDEX_WINDOW_SIZE]; /* store previous calculated voltage integral(energy) value */
+       double last_pwr_bchg;  /* store the battery power available just before charging start */
+
        /* wall clock time stamp when last event happened in seconds */
        time_t last_event_wall_time;
+       time_t last_clock_tick;
 
        /*
         * reset mark is set when battery is charged in over 90% and
@@ -172,6 +221,12 @@ struct battery_status {
        struct battery_prediction prediction[MAX_CHARGER_STATE];
 };
 
+struct thread_data {
+       char *key;
+       void *data;
+       int len;
+};
+
 static int default_sec_per_cap[MAX_CHARGER_STATE][DEFAULT_VALUE_MAX] = {
        { 70, 670, 3600 }, /* DISCHARGING MIN: 70s, AVG: 670s, MAX: 1 hour */
        { 30, 80, 3600 }    /* CHARGING MIN: 30s, AVG: 80s,  MAX: 1 hour */
@@ -196,6 +251,88 @@ static pthread_mutex_t heart_battery_mutex = PTHREAD_MUTEX_INITIALIZER;
 static time_t last_file_commit_time;
 static int battery_learning_mode;
 
+static int ocv_degree; /* Degree of the OCV and SOC polynomial */
+static double *intg;   /* Co-efficients of the OCV and SOC polynomial */
+static double pivot_nor;  /* time pivot for normal mode */
+static double pivot_ups; /* time pivot for UPS mode */
+static double volt_intg_full; /* 100% battery voltage integral(engery) value */
+static bool data_avail_chg = false; /* 5 readings in charging mode */
+ /*
+ * variable to hold the current device mode(NORMAL, PS & UPS)
+ */
+static int device_mode = POWER_NORMAL_MODE;
+/*
+ * Given the 'SOC', remaining energy of the cell can be predicted. New battery
+ * remaining time estimation logic will calculating the remaining energy as
+ * 'curr_volt_intg'.
+ *
+ * Based on estimated average power(P), a time estimate can be calcluated.
+ * Power can be estimated based on constant SOC interval Ps and constant
+ * time interval Pt.
+ *
+ * At high usage Ps will be short term average power and Pt will be long term
+ * average power.
+ *
+ * At low usage Ps will be long term average power and Pt will be short term
+ * average power.
+ *
+ * The new logic will calculate the average power 'batt_pwr' from Ps and Pt.
+ *
+ * Under-relaxation is a popular and effective technique of stabilizing prediction.
+ * The predicted time is stabilized around a pivot, which is calculated from the
+ * high-usage time and low-usage time
+ *
+ * The new logic will calculated 'pivot_nor' and 'pivot_ups' for normal and UPS
+ * mode respectively
+ *
+ * Finally, using current available energy(curr_volt_intg), average power(batt_pwr)
+ * and pivot time (pivot_nor or pivot_ups) this new logic will estimate the Battery
+ * Remaining Time for normal mode and UPS mode
+ */
+/*
+ * new battery remaining time estimation logic
+ */
+static int logic_v2;
+/*
+ * Total time taken in minutes when device is discharging at fastest rate
+ */
+static int discharge_fast;
+/*
+ * Total time taken in minutes when device is discharging at slowest rate
+ */
+static int discharge_slow;
+/*
+ * Avarage power consumed in UPS mode
+ */
+static double average_pwr;
+/*
+ * Total battery capacity in minutes(mAM)
+ */
+static int total_battery_capacity;
+/*
+ * This variable indicates first battery level update after charger insert
+ */
+static bool first_level_change = FALSE;
+/*
+ * This variable indicates the battery header used in heart.conf file
+ */
+static char battery_header[BATTERY_LINE_MAX] = "BATTERY";
+
+int heart_battery_get_capacity(void)
+{
+       return batt_stat.curr_capacity;
+}
+
+enum charger_status_type heart_battery_get_charger_status(void)
+{
+       return batt_stat.curr_charger_status;
+}
+
+enum discharge_rate_level_type heart_battery_get_discharge_rate_level(void)
+{
+       return batt_stat.discharge_rate_level;
+}
+
 inline void heart_battery_set_usage_reset_stime(int history, time_t start_time)
 {
        batt_stat.batt_reset_usage[history].start_time = start_time;
@@ -206,18 +343,18 @@ inline time_t heart_battery_get_usage_reset_stime(int history)
        return batt_stat.batt_reset_usage[history].start_time;
 }
 
-inline void heart_battery_set_usage_reset(int history, int status, long sec_per_cap, long cap_counter)
+inline void heart_battery_set_usage_reset(int history, enum charger_status_type status, long sec_per_cap, long cap_counter)
 {
        batt_stat.batt_reset_usage[history].sec_per_cap[status] = sec_per_cap;
        batt_stat.batt_reset_usage[history].cap_counter[status] = cap_counter;
 }
 
-inline long heart_battery_get_usage_reset_total_time(int history, int status)
+inline long heart_battery_get_usage_reset_total_time(int history, enum charger_status_type status)
 {
        return batt_stat.batt_reset_usage[history].sec_per_cap[status] * batt_stat.batt_reset_usage[history].cap_counter[status];
 }
 
-inline long heart_battery_get_usage_reset_count(int history, int status)
+inline long heart_battery_get_usage_reset_count(int history, enum charger_status_type status)
 {
        return batt_stat.batt_reset_usage[history].cap_counter[status];
 }
@@ -232,33 +369,33 @@ inline time_t heart_battery_get_usage_level_stime(int level)
        return batt_stat.batt_lvl_usage[level].start_time;
 }
 
-inline void heart_battery_set_usage_level(int level, int status, long sec_per_cap, long cap_counter)
+inline void heart_battery_set_usage_level(int level, enum charger_status_type status, long sec_per_cap, long cap_counter)
 {
        batt_stat.batt_lvl_usage[level].sec_per_cap[status] = sec_per_cap;
        batt_stat.batt_lvl_usage[level].cap_counter[status] = cap_counter;
 }
 
-inline long heart_battery_get_usage_level_total_time(int level, int status)
+inline long heart_battery_get_usage_level_total_time(int level, enum charger_status_type status)
 {
        return batt_stat.batt_lvl_usage[level].sec_per_cap[status] * batt_stat.batt_lvl_usage[level].cap_counter[status];
 }
 
-inline long heart_battery_get_usage_level_spc(int level, int status)
+inline long heart_battery_get_usage_level_spc(int level, enum charger_status_type status)
 {
        return batt_stat.batt_lvl_usage[level].sec_per_cap[status];
 }
 
-inline long heart_battery_get_usage_level_count(int level, int status)
+inline long heart_battery_get_usage_level_count(int level, enum charger_status_type status)
 {
        return batt_stat.batt_lvl_usage[level].cap_counter[status];
 }
 
-inline long heart_battery_get_usage_week_total_time(int day, int status)
+inline long heart_battery_get_usage_week_total_time(int day, enum charger_status_type status)
 {
        return batt_stat.week_day_usage[day].sec_per_cap[status] * batt_stat.week_day_usage[day].cap_counter[status];
 }
 
-inline long heart_battery_get_usage_week_count(int day, int status)
+inline long heart_battery_get_usage_week_count(int day, enum charger_status_type status)
 {
        return batt_stat.week_day_usage[day].cap_counter[status];
 }
@@ -277,6 +414,14 @@ inline int heart_battery_get_learning_mode(void)
 {
        int i, count = 0;
 
+       if (logic_v2) { /* new logic */
+               /*wait till enough data gets collected to estimated battery remaining time */
+               if (batt_stat.data_available == TRUE) {
+                       return 1;
+               }
+               return 0;
+       }
+        /* old logic */
        for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
                if (heart_battery_get_usage_week_stime(i))
                        count++;
@@ -286,20 +431,20 @@ inline int heart_battery_get_learning_mode(void)
        return 0;
 }
 
-inline void heart_battery_set_usage_week(int day, int status, long sec_per_cap, long cap_counter)
+inline void heart_battery_set_usage_week(int day, enum charger_status_type status, long sec_per_cap, long cap_counter)
 {
        batt_stat.week_day_usage[day].sec_per_cap[status] = sec_per_cap;
        batt_stat.week_day_usage[day].cap_counter[status] = cap_counter;
 }
 
-inline void heart_battery_set_prediction(int strategy, int status, long sec_per_cap, long cap_counter, long pred_min)
+inline void heart_battery_set_prediction(int strategy, enum charger_status_type status, long sec_per_cap, long cap_counter, long pred_min)
 {
        batt_stat.prediction[status].sec_per_cap[strategy] = sec_per_cap;
        batt_stat.prediction[status].cap_counter[strategy] = cap_counter;
        batt_stat.prediction[status].time_pred_min[strategy] = pred_min;
 }
 
-inline long heart_battery_get_prediction_time(int strategy, int status)
+inline long heart_battery_get_prediction_time(int strategy, enum charger_status_type status)
 {
        return batt_stat.prediction[status].time_pred_min[strategy];
 }
@@ -314,13 +459,98 @@ inline void heart_battery_set_file_commit_timestamp(time_t timestamp)
        last_file_commit_time = timestamp;
 }
 
+static void *async_db_task(void *data)
+{
+       char *key;
+       struct battery_used *used;
+       struct battery_status *status;
+       struct thread_data *pdata = (struct thread_data *)data;
+       if (!pdata) {
+               _E("Invalid Argument");
+               return NULL;
+       }
+       key = pdata->key;
+
+       _D("Task Key : %s", key);
+       if (!strncmp(BATTERY_USED_TIME, key, sizeof(BATTERY_USED_TIME) + 1)) {
+               used = (struct battery_used *)pdata->data;
+               logging_leveldb_putv(key, strlen(key), "%d %d ",
+                   used->used_time_sec, used->last_update_time);
+       } else if (!strncmp(BATTERY_STATUS, key, sizeof(BATTERY_STATUS) + 1)) {
+               status = (struct battery_status *)pdata->data;
+               logging_leveldb_putv(key, strlen(key), "%d %ld %ld %ld %ld %d %d ",
+                   status->curr_capacity,
+                   status->curr_run_time_sec[DISCHARGING],
+                   status->curr_cap_counter[DISCHARGING],
+                   status->curr_run_time_sec[CHARGING],
+                   status->curr_cap_counter[CHARGING],
+                   status->curr_charger_status,
+                   status->reset_mark);
+       } else if (!strncmp(BATTERY_RESET_USAGE, key, sizeof(BATTERY_RESET_USAGE) + 1) ||
+                       !strncmp(BATTERY_WEEK_DAY_USAGE, key, sizeof(BATTERY_WEEK_DAY_USAGE) + 1) ||
+                       !strncmp(BATTERY_LEVEL_USAGE, key, sizeof(BATTERY_LEVEL_USAGE) + 1) ||
+                       !strncmp(BATTERY_PREDICTION, key, sizeof(BATTERY_PREDICTION) + 1)) {
+               logging_leveldb_put(key, strlen(key), (char *)pdata->data, pdata->len);
+       }
+       free(pdata);
+       return NULL;
+}
+
+static void update_db(char *key, void *data, int len)
+{
+       pthread_t thread_id;
+       int ret;
+       pthread_attr_t attr;
+
+       struct thread_data *pdata = (struct thread_data *)malloc(sizeof(struct thread_data));
+       if (!pdata) {
+               _E("malloc failed");
+               return;
+       }
+       pdata->key = key;
+       pdata->data = data;
+       pdata->len = len;
+
+       ret = pthread_attr_init(&attr);
+       if (ret)
+               _E("pthread pthread_attr_init failed, %d",  ret);
+
+       ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
+       if (ret)
+               _E("pthread pthread_attr_setdetachstate failed, %d",  ret);
+
+       ret = pthread_create(&thread_id, &attr, (void *)async_db_task, (void *)pdata);
+       if (ret) {
+               _E("pthread creation for async_task failed, %d",  ret);
+               free(pdata);
+       }
+}
+
+static int heart_battery_calculate_discharge_rate_level(long spc)
+{
+       long gap, total_spc;
+
+       total_spc = batt_stat.prediction[DISCHARGING].sec_per_cap[TA];
+       if (!total_spc)
+               return BATTERY_DISCHARGE_NONE;
+       gap = (total_spc * DISCHARGE_BASE_RATE);
+
+       _I("total: %ld, spc: %ld, gap: %ld", total_spc, spc, gap);
+
+       if (total_spc + gap < spc)
+               return BATTERY_DISCHARGE_LOW;
+       else if (total_spc - gap > spc)
+               return BATTERY_DISCHARGE_HIGH;
+
+       return BATTERY_DISCHARGE_AVG;
+}
+
 static int heart_battery_save_used_time(char *key, struct battery_used *used)
 {
        if (!key || !used)
                return RESOURCED_ERROR_FAIL;
 
-       logging_leveldb_putv(key, strlen(key), "%d %d ",
-                       used->used_time_sec, used->last_update_time);
+       update_db(key, used, 0);
        return RESOURCED_ERROR_NONE;
 };
 
@@ -329,14 +559,7 @@ static int heart_battery_save_status(char *key, struct battery_status *status)
        if (!key || !status)
                return RESOURCED_ERROR_FAIL;
 
-       logging_leveldb_putv(key, strlen(key), "%d %ld %ld %ld %ld %d %d ",
-                       status->curr_capacity,
-                       status->curr_run_time_sec[DISCHARGING],
-                       status->curr_cap_counter[DISCHARGING],
-                       status->curr_run_time_sec[CHARGING],
-                       status->curr_cap_counter[CHARGING],
-                       status->curr_charger_status,
-                       status->reset_mark);
+       update_db(key, status, 0);
        return RESOURCED_ERROR_NONE;
 };
 
@@ -357,7 +580,7 @@ static int heart_battery_save_usage(char *key, struct battery_usage *usage, int
                                usage[i].sec_per_cap[CHARGING],
                                usage[i].cap_counter[CHARGING]);
        }
-       logging_leveldb_put(key, strlen(key), buf, len);
+       update_db(key, buf, len);
        return RESOURCED_ERROR_NONE;
 };
 
@@ -378,7 +601,7 @@ static int heart_battery_save_prediction(char *key, struct battery_prediction *p
                                prediction[CHARGING].cap_counter[i],
                                prediction[CHARGING].time_pred_min[i]);
        }
-       logging_leveldb_put(key, strlen(key), buf, len);
+       update_db(key, buf, len);
        return RESOURCED_ERROR_NONE;
 };
 
@@ -485,12 +708,17 @@ static int heart_battery_load_usage(char *key, struct battery_usage *usage, int
 
        ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
        if (ret != RESOURCED_ERROR_NONE) {
-               _E("Failed to read leveldb key: %s", key);
+               _E("Failed to read leveldb key");
                return RESOURCED_ERROR_FAIL;
        }
+
+       if (buf[0] == '\0') {
+               _D("There is no history about %s", key);
+               return RESOURCED_ERROR_NONE;
+       }
+
        i = 0;
        num = total_size/sizeof(struct battery_usage);
-
        token = strtok_r(buf, " ", &saveptr);
        if (!token) {
                _E("Failed to token value");
@@ -588,7 +816,7 @@ static int heart_battery_load_prediction(char *key, struct battery_prediction *p
        return RESOURCED_ERROR_NONE;
 };
 
-static void heart_battery_update_used_time(time_t now, int status)
+static void heart_battery_update_used_time(time_t now, enum charger_status_type status)
 {
        if (batt_used.last_charger_status == DISCHARGING)
                batt_used.used_time_sec +=
@@ -627,7 +855,7 @@ static int heart_battery_get_capacity_history_size(void)
 
 static void heart_battery_insert_capacity(GSList **history_list, int capacity,
                int diff_capacity, time_t timestamp, long used_time, long charging_time,
-               int charger_status, int reset_mark, int clear)
+               enum charger_status_type charger_status, int reset_mark, int clear)
 {
        static int old_reset_mark = 0;
        GSList *iter, *next;
@@ -846,6 +1074,480 @@ static void heart_battery_save_to_file(bool force)
        heart_battery_set_file_commit_timestamp(now);
 }
 
+/*
+ * This function will open the '.battery_data.dat' file and write all battery
+ * related data into it.
+ */
+static void heart_battery_write_data_to_file(void)
+{
+       int i;
+       int len = 0;
+       char buff[BATTERY_DATA_MAX] = {0,0};
+       _cleanup_fclose_ FILE *fp = NULL;
+
+       fp = fopen(HEART_BATTERY_DATA_FILE, "w");
+       if (fp == NULL) {
+               _E("Could not open file battery_data file\n");
+               return;
+       }
+
+       for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+               len += snprintf(buff + len, BATTERY_DATA_MAX - len, "%ld %lf\n", \
+                       batt_stat.last_wall_time[i], batt_stat.last_volt_intg[i]);
+
+               if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
+                       fputs(buff, fp);
+                       len = 0;
+               }
+       }
+       len += snprintf(buff + len, BATTERY_DATA_MAX - len, "%d %d %d %d %lf %d", \
+               batt_stat.curr_index, batt_stat.last_capacity,batt_stat.remaining_time, \
+               batt_stat.remaining_time_ups, batt_stat.last_pwr_bchg, batt_stat.data_available);
+
+       fputs(buff, fp);
+}
+
+/*
+ * This function will open the '.battery_data.dat' file and read all battery
+ * related data from it and store in variable 'batt_stat'
+ */
+static void heart_battery_read_data_from_file(void)
+{
+       int i;
+       int len = 0;
+       char buff[BATTERY_DATA_MAX] = {0,0};
+       char *ch;
+       _cleanup_fclose_ FILE *fp = NULL;
+
+       fp = fopen(HEART_BATTERY_DATA_FILE, "r");
+       if (fp == NULL) {
+               _E("Could not open battery_data file\n");
+               return;
+       }
+
+       for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+               ch = fgets(buff, BATTERY_DATA_MAX, fp);
+               if (ch == NULL)
+                       /*if file is empty then return from here */
+                       return;
+
+               len += sscanf(buff, "%ld %lf", \
+                               &batt_stat.last_wall_time[i], &batt_stat.last_volt_intg[i]);
+       }
+
+       ch = fgets(buff, BATTERY_DATA_MAX, fp);
+       if (ch != NULL)
+               len += sscanf(buff, "%d %d %d %d %lf %d", \
+                       &batt_stat.curr_index, &batt_stat.last_capacity, &batt_stat.remaining_time, \
+                       &batt_stat.remaining_time_ups, &batt_stat.last_pwr_bchg, &batt_stat.data_available);
+}
+
+/*
+ * This function will reject all the battery related data which were stored earlier
+ */
+static void heart_battery_reject_data(void)
+{
+       int i;
+
+       for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+               batt_stat.last_wall_time[i] = 0;
+               batt_stat.last_volt_intg[i] = 0.0;
+       }
+
+       /* Do not reject this, once data available, do not change untill next binary flash */
+       /*batt_stat.data_available = 0;   */
+       batt_stat.last_capacity = 0;
+       batt_stat.curr_index = 0;
+       batt_stat.remaining_time = 0;
+       batt_stat.remaining_time_ups = 0;
+       /* do not flush this value. When proper power value is not present, previously
+       calculated power only will be used. */
+       /*batt_stat.last_pwr_bchg = 0.0;  */
+
+       heart_battery_write_data_to_file();
+}
+
+/*
+ * This function will calculate the voltage integral(energy) at battery level 100.
+ * We will calculate Pivot using fast discharge and slow discharge rate for
+ * estimating the battery time in normal mode
+ */
+static void heart_battery_calculate_pivot(void)
+{
+       int i;
+
+       for (i = 0; i < ocv_degree; i++) {
+               volt_intg_full += (intg[i] /(i+1)) * pow(100 , i+1);
+       }
+       volt_intg_full = volt_intg_full/100000.0;
+
+       pivot_nor = ((sqrt(discharge_fast) + sqrt(discharge_slow))/2);
+       pivot_nor = pivot_nor * pivot_nor; // taking square of Tpivot
+
+       pivot_ups = ((sqrt(discharge_fast*UPS_FACTOR) + sqrt(discharge_slow*UPS_FACTOR))/2);
+       pivot_ups = pivot_ups * pivot_ups; // taking square of Tpivot
+}
+
+/* function to return the time(in seconds) since the  Epoch*/
+static long heart_battery_logging_get_time_sec_new(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       return (tv.tv_sec + tv.tv_usec / 1000000);
+}
+
+/*
+ * This function will read the current time and will compare with previously stored time.
+ * If time difference is more then it is assumed that device was powered off and it will
+ * adjust all stored time values
+ */
+static void heart_battery_power_off_time_adjustment(void)
+{
+       int i;
+       int index;
+       int clock_tick_diff = 0;
+       long int curr_time;
+       long int time_diff = 0;
+
+       curr_time = heart_battery_logging_get_time_sec_new();
+
+       index = ((batt_stat.curr_index - 1) + INDEX_WINDOW_SIZE) % INDEX_WINDOW_SIZE;
+       if (batt_stat.last_wall_time[index] == 0)
+               index = 0;
+
+       clock_tick_diff = logging_get_time(CLOCK_BOOTTIME) - batt_stat.last_clock_tick;
+
+       /* check if we have store last time value or not */
+       if (batt_stat.last_wall_time[index] != 0) {
+               time_diff = curr_time - batt_stat.last_wall_time[index];
+               time_diff -= clock_tick_diff;
+       }
+
+       _I("All store time value will be scaled up by %ld secs\n", time_diff);
+
+       /*scale up all stored time value */
+       for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+               if (batt_stat.last_wall_time[i] == 0) {
+                       /* we do not have stored time value from this point onwards, stop updating*/
+                       break;
+               }
+               else
+                       batt_stat.last_wall_time[i] += time_diff;
+       }
+
+       /* update same value in battery data file*/
+       heart_battery_write_data_to_file();
+
+       /*
+        * during charge time
+        */
+       time_diff = curr_time - batt_stat.last_wall_time_chg;
+       time_diff -= clock_tick_diff;
+       /*
+         * update last_wall_time_chg as per previous and new time diff
+         * it will take care of positive of negative difference
+         */
+       batt_stat.last_wall_time_chg += time_diff;
+       _I("last_wall_time_chg got updated by %d\n", time_diff);
+       /*
+         * make first_level_change as TRUE so that charge remaining time
+         * should not vary much
+         */
+       first_level_change = TRUE;
+}
+
+/*
+ * In case of any time change in the device, this callback get called and it
+ * will do the time adjustment
+ */
+static void time_change_notify_cb(keynode_t *key, void *data)
+{
+       heart_battery_power_off_time_adjustment();
+}
+
+static int get_battery_remaining_time_new(void)
+{
+       return batt_stat.remaining_time;
+}
+
+static int get_battery_remaining_time_ups()
+{
+       return batt_stat.remaining_time_ups;
+}
+
+/*
+ * This function will return the average of stored time diff values
+ */
+static int heart_battery_get_time_diff_avg(int time_diff_avg)
+{
+       int temp_index;
+       int i;
+
+       if (data_avail_chg == true) {
+               /*
+                * calculate the average of last 5(including current) time diff values
+                */
+               temp_index = ((batt_stat.index_chg-1) + BATTERY_LEVEL_GAP) % BATTERY_LEVEL_GAP;
+               for (i = 1; i < BATTERY_LEVEL_GAP; i++) {
+                       time_diff_avg += batt_stat.last_wall_time_chg_diff[temp_index];
+                       temp_index = ((temp_index-1) + BATTERY_LEVEL_GAP) % BATTERY_LEVEL_GAP;
+               }
+               time_diff_avg = time_diff_avg/BATTERY_LEVEL_GAP;
+       } else {
+               /*
+                * take average of only available data. Do not include 1st value so
+                * i stared from 1.
+                */
+               for (i = 1; i < batt_stat.index_chg; i++)
+                       time_diff_avg += batt_stat.last_wall_time_chg_diff[i];
+
+               time_diff_avg = time_diff_avg/i;
+       }
+       /*
+        * to minimize the time diff fluctuation
+        */
+       time_diff_avg = (time_diff_avg+BATTERY_C_RATE)/2;
+       _I("time_diff after averaging= %d\n", time_diff_avg);
+
+       return time_diff_avg;
+}
+
+/*
+ * This function will return the time diff between last and current battery
+ * level change
+ */
+int heart_battery_get_time_diff(long curr_wall_time)
+{
+       if (batt_stat.last_wall_time_chg == 0)
+               /*
+                * First time estimation
+                * In this case charge rate will be considered as time diff
+                */
+               return BATTERY_C_RATE;
+
+       return (curr_wall_time - batt_stat.last_wall_time_chg);
+}
+
+/*
+ * This function will calculate the battery charging remaining time
+ */
+static void heart_battery_cal_charging_rem_time(void)
+{
+       long curr_wall_time = 0;
+       int rem_time;
+       int time_diff;
+       int time_diff_avg;
+
+       if (batt_stat.last_capacity_chg == batt_stat.curr_capacity) {
+               _I("Last capacity %d is same as current capacity %d\n",
+                       batt_stat.last_capacity_chg, batt_stat.curr_capacity);
+               return;
+       }
+
+       curr_wall_time = heart_battery_logging_get_time_sec_new();
+
+       time_diff = heart_battery_get_time_diff(curr_wall_time);
+
+       /*
+        * just after inserting the charger, if time diff between two level
+        * is less than MIN_TIME_FOR_LVL_CHANGE value then consider time diff
+        * as BATTERY_C_RATE so that there will not be sudden fall in charge
+        * remaining time
+        */
+       if (time_diff < MIN_TIME_FOR_LVL_CHANGE && first_level_change == TRUE) {
+               /*
+                * first_level_change will be set to TRUE in function
+                * heart_battery_charger_status() and set to FALSE in function
+                * heart_battery_capacity_status()
+                */
+               _I("time diff %d is less than min value of lvl change %d\n",time_diff, MIN_TIME_FOR_LVL_CHANGE);
+               time_diff = BATTERY_C_RATE;
+       }
+
+       _I("data_avail_chg = %d, index_chg = %d\n",data_avail_chg, batt_stat.index_chg);
+       _I("last_wall_time_chg = %ld, curr_wall_time = %ld\n", batt_stat.last_wall_time_chg, curr_wall_time);
+       _I("time diff before averaging = %d\n",time_diff);
+
+       /*
+        * get the average of all time diff values stored including current
+        */
+       time_diff_avg = heart_battery_get_time_diff_avg(time_diff);
+
+       if (batt_stat.curr_capacity == FULL_CAPACITY) {
+               batt_stat.remaining_time_chg = 0;
+       } else {
+               /*
+                * calculate the remaining charge time based on constant current
+                * and constant votlage(CCCV) logic. 'time_diff_avg' is for CC and
+                * square(time_diff_avg/BATTERY_C_RATE) is for CV part.
+                */
+               rem_time = (time_diff_avg + (time_diff_avg/BATTERY_C_RATE)*(time_diff_avg/BATTERY_C_RATE))*(FULL_CAPACITY- batt_stat.curr_capacity);
+               batt_stat.remaining_time_chg = SEC_TO_MIN(rem_time);
+       }
+
+       batt_stat.last_wall_time_chg = curr_wall_time;
+       batt_stat.last_wall_time_chg_diff[batt_stat.index_chg] = time_diff;
+       batt_stat.index_chg = (batt_stat.index_chg+1)%BATTERY_LEVEL_GAP;
+       batt_stat.last_capacity_chg = batt_stat.curr_capacity;
+       batt_stat.last_clock_tick =  logging_get_time(CLOCK_BOOTTIME);
+
+       _I("Capacity = %d, charging remaining time = %d\n", batt_stat.curr_capacity, batt_stat.remaining_time_chg);
+
+       if (batt_stat.index_chg+1 == BATTERY_LEVEL_GAP)
+               data_avail_chg = true;
+}
+
+
+/*
+ * This function will calculate the battery estimation time for every battery
+ * level change
+ */
+static void heart_battery_cal_discharge_rem_time(void)
+{
+       double curr_volt_intg = 0;
+       double volt_intg_diff = 0;
+       double ps, pt;
+       double batt_pwr;
+       int rem_time = 0;
+       int index = 0;
+       int temp_index = 0;
+       int index_count;
+       int i;
+       int update_time;
+       long curr_wall_time = 0;
+       long time_diff1, time_diff2;
+
+       _I("last capacity = %d, current capacity = %d\n",batt_stat.last_capacity, batt_stat.curr_capacity);
+
+       /* if battery level change happen then only calculate the new time*/
+       if (batt_stat.last_capacity != batt_stat.curr_capacity) {
+               /* calculate the voltage integral(energy) for current capacity */
+               for (i = 0; i < ocv_degree; i++) {
+                       curr_volt_intg += (intg[i] /(i+1)) * pow(batt_stat.curr_capacity , i+1);
+               }
+               curr_volt_intg = curr_volt_intg /100000.0;
+
+               /*current time*/
+               curr_wall_time = heart_battery_logging_get_time_sec_new();
+
+               _I("curr_volt_intg = %lf, curr_wall_time = %ld\n", curr_volt_intg, curr_wall_time);
+
+               if (batt_stat.last_capacity < batt_stat.curr_capacity) {
+                       /*
+                       *this indicates that device was put for charging so need to reject all the previous data except
+                       *'batt_stat.data_available' and 'batt_stat.last_pwr_bchg'.
+                       *Use last available battery power before connecting the charger as current average power.
+                       */
+                       batt_pwr = batt_stat.last_pwr_bchg;
+                       heart_battery_reject_data();
+               }
+               else {
+                       index = ((batt_stat.curr_index - BATTERY_LEVEL_GAP) + INDEX_WINDOW_SIZE)%INDEX_WINDOW_SIZE;
+                       if (batt_stat.last_wall_time[index] == 0 && batt_stat.last_volt_intg[index] == 0) {
+                               /* do not have enough previous data so take 1st stored data as reference */
+                               time_diff1 = curr_wall_time - batt_stat.last_wall_time[0];
+                               volt_intg_diff = batt_stat.last_volt_intg[0] - curr_volt_intg;
+                               if (volt_intg_diff < DOUBLE_ZERO)
+                                       volt_intg_diff = volt_intg_full - curr_volt_intg;
+                       }
+                       else {
+                               /* time differenc since last battery level change*/
+                               time_diff1 = curr_wall_time - batt_stat.last_wall_time[index];
+                               /* voltage integral(energy) change since last battery level change */
+                               volt_intg_diff = batt_stat.last_volt_intg[index] - curr_volt_intg;
+                       }
+                       _I("time_diff1 = %d, volt_intg_diff = %lf\n", time_diff1, volt_intg_diff);
+
+                       time_diff1 = SEC_TO_MIN(time_diff1); /*convert second to minute */
+
+                       /* calculate short term average power component*/
+                       if (time_diff1 != 0)
+                               ps = (total_battery_capacity *volt_intg_diff) / time_diff1;
+                       else
+                               ps = 0;
+
+                       _I("ps = %lf\n", ps);
+
+                       /* find the voltage integral(energy) of 1 hr back battery level.
+                       1. Place the index at proper location
+                       2. get the time stored at that index
+                       3. if difference between last time and current time is >= 60 then take that voltage integral
+                       */
+                       index_count = INDEX_WINDOW_SIZE;
+                       time_diff2 = 0;
+                       temp_index = BATTERY_WINDOW_INDEX(batt_stat.curr_index - 1);
+                       while ((index_count > 0) && (time_diff2 < 60)) {
+                               if  (batt_stat.last_wall_time[temp_index] == 0)
+                                       /* data not available so break the loop */
+                                       break;
+
+                               time_diff2 = SEC_TO_MIN(curr_wall_time - batt_stat.last_wall_time[temp_index]);
+                               temp_index = BATTERY_WINDOW_INDEX(temp_index - 1);
+                               index_count--;
+                       }
+
+                       /* calculate long term average power component*/
+                       if (time_diff2 < 60) {
+                               pt = 0;
+                       } else {
+                               temp_index = BATTERY_WINDOW_INDEX(temp_index + 1);
+                               volt_intg_diff = batt_stat.last_volt_intg[temp_index] - curr_volt_intg ;
+                               if (volt_intg_diff < DOUBLE_ZERO)
+                                       pt = 0;
+                               else
+                                       pt = (total_battery_capacity  * volt_intg_diff) / time_diff2;
+                       }
+
+                       _I("time_diff2 = %d, volt_intg_diff = %lf, pt = %lf\n", time_diff2, volt_intg_diff, pt);
+
+                       /* calculate the average power from the short component and long component*/
+                       if ((pt + ps) != 0)
+                               batt_pwr = (((pt  * pt) + (ps * ps)) / (pt + ps));
+                       else
+                               batt_pwr = batt_stat.last_pwr_bchg;
+               }
+
+               /* total remaining time based on current battery level*/
+               rem_time = (total_battery_capacity * curr_volt_intg) / batt_pwr;
+
+               _I("pivot_nor = %lf, curr_volt_intg = %lf , volt_intg_full %lf, batt_pwr = %lf", pivot_nor, curr_volt_intg,volt_intg_full, batt_pwr);
+
+               /* calculate remaining time for normal mode */
+               update_time = (pivot_nor * curr_volt_intg)/volt_intg_full;
+               batt_stat.remaining_time = (LONG_TIME_WEIGHT*update_time + SHORT_TIME_WEIGHT*CAL_MIN(update_time, rem_time));
+
+                /* calculate remaining time for UPS mode */
+               update_time = (pivot_ups * curr_volt_intg)/volt_intg_full;
+               batt_stat.remaining_time_ups = (LONG_TIME_WEIGHT*update_time + SHORT_TIME_WEIGHT*CAL_MIN(update_time, rem_time));
+
+               _I("normal mode remaining time = %d, ups remaining time = %d\n",
+                       batt_stat.remaining_time, batt_stat.remaining_time_ups);
+
+               batt_stat.last_volt_intg[batt_stat.curr_index] = curr_volt_intg;
+               batt_stat.last_wall_time[batt_stat.curr_index] = curr_wall_time;
+               batt_stat.last_capacity = batt_stat.curr_capacity;
+               batt_stat.curr_index = (batt_stat.curr_index + 1) % INDEX_WINDOW_SIZE;
+               batt_stat.last_clock_tick =  logging_get_time(CLOCK_BOOTTIME);
+
+               if (batt_pwr > DOUBLE_ZERO) {
+                       /*when battery percentage is 0 then available power will be 0 so do not store this value.
+                       keep previous value only. */
+                       batt_stat.last_pwr_bchg = batt_pwr;
+               }
+
+               if (batt_stat.curr_index > BATTERY_LEVEL_GAP) {
+                       /* When enough data to estimate the available battery time are stored, no need to update the status
+                       of batt_stat.data_available  untill we are flashing new binary. */
+                       batt_stat.data_available = TRUE;
+               }
+
+               /* save all calculated battery data to file*/
+               heart_battery_write_data_to_file();
+       }
+}
+
 void heart_battery_update(struct logging_table_form *data, void *user_data)
 {
        heart_battery_save_to_file(false);
@@ -967,7 +1669,7 @@ static long heart_battery_compute_remaining_time_in_min(int capacity_count, long
        return time;
 }
 
-static void heart_battery_calculate_prediction(enum charging_goal goal)
+static void heart_battery_calculate_prediction(enum charger_status_type goal)
 {
        int i, capacity, level;
        long total_time, total_count, sec_per_cap, pred_min;
@@ -1071,12 +1773,13 @@ static void heart_battery_calculate_prediction(enum charging_goal goal)
                _E("Failed to alloc array");
                return;
        }
-       if (heart_battery_get_capacity_history_latest(arrays, goal, BATTERY_PREDICTION_LATEST_COUNT) != RESOURCED_ERROR_NONE) {
+       if (heart_battery_get_capacity_history_latest(arrays, goal, BATTERY_PREDICTION_LATEST_COUNT)
+                       != RESOURCED_ERROR_NONE) {
                _E("Failed to get battery capacity history");
+               g_array_free(arrays, TRUE);
+               arrays = NULL;
                return;
        }
-       if (!arrays->len)
-               _E("No battery capacity history data");
        total_time = 0;
        total_count = 0;
        for (i = 0; i < arrays->len; i++) {
@@ -1088,6 +1791,7 @@ static void heart_battery_calculate_prediction(enum charging_goal goal)
                        total_time += lbc->charging_time;
                else
                        total_time += lbc->used_time;
+               free(lbc);
        }
        if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
                sec_per_cap = total_time / total_count;
@@ -1099,6 +1803,12 @@ static void heart_battery_calculate_prediction(enum charging_goal goal)
                pred_min =
                        heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
                heart_battery_set_prediction(COUNT, goal, sec_per_cap, total_count, pred_min);
+               /* check current discharge rate */
+               if (sec_per_cap && goal == DISCHARGING) {
+                       batt_stat.discharge_rate_level =
+                               heart_battery_calculate_discharge_rate_level(sec_per_cap);
+                       _I("discharge rate level : %ld", batt_stat.discharge_rate_level);
+               }
        } else
                heart_battery_set_prediction(COUNT, goal, 0, 0, 0);
        g_array_free(arrays, TRUE);
@@ -1113,10 +1823,10 @@ static void heart_battery_calculate_prediction(enum charging_goal goal)
        }
        if (heart_battery_get_capacity_history(arrays, BATTERY_PREDICTION_PERIOD) != RESOURCED_ERROR_NONE) {
                _E("Failed to get battery capacity history");
+               g_array_free(arrays, TRUE);
+               arrays =  NULL;
                return;
        }
-       if (!arrays->len)
-               _E("No battery capacity history data");
        total_time = 0;
        total_count = 0;
        for (i = 0; i < arrays->len; i++) {
@@ -1124,16 +1834,21 @@ static void heart_battery_calculate_prediction(enum charging_goal goal)
                if (!lbc)
                        break;
                if (goal == CHARGING) {
-                       if (lbc->charger_status != CHARGING)
+                       if (lbc->charger_status != CHARGING) {
+                               free(lbc);
                                continue;
+                       }
                        total_time += lbc->charging_time;
                        total_count += lbc->diff_capacity;
                } else {
-                       if (lbc->charger_status != DISCHARGING)
+                       if (lbc->charger_status != DISCHARGING) {
+                               free(lbc);
                                continue;
+                       }
                        total_time += lbc->used_time;
                        total_count += lbc->diff_capacity;
                }
+               free(lbc);
        }
        g_array_free(arrays, TRUE);
        arrays = NULL;
@@ -1284,7 +1999,7 @@ static int heart_battery_add_capacity(int capacity)
 
 /* ============================ DBUS -> DEVICED on demand ==================== */
 
-static int heart_battery_get_capacity(void)
+static int heart_battery_direct_get_capacity(void)
 {
        int capacity, ret;
        DBusMessage *msg;
@@ -1306,7 +2021,7 @@ static int heart_battery_get_capacity(void)
        return capacity;
 }
 
-static int heart_battery_get_charger_status(void)
+static enum charger_status_type heart_battery_direct_get_charger_status(void)
 {
        int status, ret;
        DBusMessage *msg;
@@ -1360,6 +2075,20 @@ static void heart_battery_capacity_status(void *data, DBusMessage *msg)
        heart_battery_add_capacity(capacity);
        heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
                        batt_stat.curr_charger_status);
+
+       if (logic_v2) {
+               /* get the device mode */
+               if (vconf_get_int( VCONFKEY_HEART_BATTERY_DEVICE_MODE, &device_mode))
+                       _E("failed to get VCONFKEY_HEART_BATTERY_DEVICE_MODE\n");
+
+               /* for every battery level change, calculate the battery estimation time using new logic*/
+               heart_battery_cal_discharge_rem_time();
+
+               if (batt_stat.curr_charger_status == CHARGING) {
+                       heart_battery_cal_charging_rem_time();
+                       first_level_change = FALSE;
+               }
+       }
 }
 
 static void heart_battery_charger_status(void *data, DBusMessage *msg)
@@ -1410,6 +2139,17 @@ static void heart_battery_charger_status(void *data, DBusMessage *msg)
        heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
                        batt_stat.curr_charger_status);
        heart_battery_calculate_prediction(batt_stat.curr_charger_status);
+
+       if (logic_v2) {
+               /* If charger has been removed then update the battery estimation time */
+               heart_battery_cal_discharge_rem_time();
+
+               if (charger_status == CHARGING) {
+                       batt_stat.last_wall_time_chg = 0;
+                       first_level_change = TRUE;
+                       heart_battery_cal_charging_rem_time();
+               }
+       }
 }
 
 /* =========================  DBUS -> DEVICED handler END ==================== */
@@ -1452,12 +2192,7 @@ int heart_battery_get_capacity_history_latest(GArray *arrays, int charge, int ma
                lbci = malloc(sizeof(struct heart_battery_capacity));
                if (!lbci) {
                        _E("malloc failed");
-                       ret = pthread_mutex_unlock(&heart_battery_mutex);
-                       if (ret) {
-                               _E("pthread_mutex_unlock() failed, %d", ret);
-                               return RESOURCED_ERROR_FAIL;
-                       }
-                       return RESOURCED_ERROR_OUT_OF_MEMORY;
+                       goto unlock_exit;
                }
                lbci->capacity = lbc->capacity;
                lbci->diff_capacity = lbc->diff_capacity;
@@ -1468,6 +2203,8 @@ int heart_battery_get_capacity_history_latest(GArray *arrays, int charge, int ma
                lbci->charger_status = lbc->charger_status;
                g_array_prepend_val(arrays, lbci);
        }
+unlock_exit:
+       g_slist_free(rlist);
        ret = pthread_mutex_unlock(&heart_battery_mutex);
        if (ret) {
                _E("pthread_mutex_unlock() failed, %d", ret);
@@ -1597,6 +2334,7 @@ static DBusMessage *edbus_get_battery_capacity_history_latest(E_DBus_Object *obj
                dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &lbc->used_time);
                dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &lbc->charging_time);
                dbus_message_iter_close_container(&arr, &sub);
+               free(lbc);
        }
        dbus_message_iter_close_container(&d_iter, &arr);
 exit:
@@ -1696,7 +2434,7 @@ static DBusMessage *edbus_get_battery_used_time(E_DBus_Object *obj, DBusMessage
        return reply;
 }
 
-static int get_battery_remaining_time(int mode, int status)
+static int get_battery_remaining_time(int mode, enum charger_status_type status)
 {
        int i, ret, count;
        long sum, time, cumul_average, trend_average;
@@ -1742,10 +2480,33 @@ static int get_battery_remaining_time(int mode, int status)
        } else
                ret = ((cumul_average * CUMUL_WEIGHT) + (trend_average * TREND_WEIGHT));
 
-       if (status == CHARGING)
+       if (status == CHARGING) {
+               if (logic_v2)  /* new logic */
+                       return batt_stat.remaining_time_chg;
+               return ret; /* old logic */
+       }
+
+       if (logic_v2) { /* new logic */
+               switch (mode) {
+               case POWER_SAVING_MODE:
+                       /* Fall through */
+               case ULTRA_SAVING_MODE:
+                       ret = get_battery_remaining_time_ups();
+                       break;
+               case POWER_NORMAL_MODE:
+                       ret = get_battery_remaining_time_new();
+                       break;
+               default:
+                       break;
+               }
                return ret;
+       }
 
-       switch (mode) {
+       if (ret <= 0)
+               return BATTERY_USAGE_LEARNING;
+
+        /* old logic */
+       switch(mode){
        case ULTRA_SAVING_MODE:
                /* Fall through */
        case POWER_SAVING_MODE:
@@ -1804,6 +2565,22 @@ static DBusMessage *edbus_get_battery_charging_time(E_DBus_Object *obj, DBusMess
        return reply;
 }
 
+static DBusMessage *edbus_get_battery_discharge_rate_level(E_DBus_Object *obj, DBusMessage *msg)
+{
+       DBusMessage *reply;
+       DBusMessageIter iter;
+       int ret;
+
+       ret = batt_stat.discharge_rate_level;
+
+       reply = dbus_message_new_method_return(msg);
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+       _I("discharge_rate_level %d", ret);
+
+       return reply;
+}
+
 static DBusMessage *edbus_battery_save_to_file(E_DBus_Object *obj, DBusMessage *msg)
 {
        int ret;
@@ -1835,11 +2612,12 @@ static struct edbus_method edbus_methods[] = {
        { "GetBatteryUsedTime",   NULL,   "i", edbus_get_battery_used_time },
        { "GetBatteryRemainingTime",   "i",   "i", edbus_get_battery_remaining_time },
        { "GetBatteryChargingTime",   NULL,   "i", edbus_get_battery_charging_time },
+       { "GetBatteryDischargeRateLevel",   NULL,   "i", edbus_get_battery_discharge_rate_level },
        { "SaveBatteryData",   NULL,   "i", edbus_battery_save_to_file },
 };
 
 /* =========================  DBUS interface END ==================== */
-static void heart_battery_used_time_init(int status)
+static void heart_battery_used_time_init(enum charger_status_type status)
 {
        batt_used.last_charger_status = status;
        batt_used.last_update_time = logging_get_time(CLOCK_BOOTTIME);
@@ -1885,21 +2663,70 @@ static void heart_battery_status_init(void)
        if (ret < 0)
                _E("Failed to read battery status data");
 
+       if (logic_v2) {
+               for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+                       batt_stat.last_wall_time[i] = 0;
+                       batt_stat.last_volt_intg[i] = 0.0;
+               }
+               for (i = 0; i < BATTERY_LEVEL_GAP; i++)
+                       batt_stat.last_wall_time_chg_diff[i] = 0;
+
+               batt_stat.data_available = 0;
+               batt_stat.last_capacity = 0;
+               first_level_change = FALSE;
+               batt_stat.curr_index = 0;
+               batt_stat.remaining_time = 0;
+               batt_stat.remaining_time_ups = 0;
+               batt_stat.last_pwr_bchg = average_pwr;
+               batt_stat.last_wall_time_chg = 0;
+               batt_stat.index_chg = 0;
+               batt_stat.remaining_time_chg = 0;
+               batt_stat.last_clock_tick =  logging_get_time(CLOCK_BOOTTIME);
+
+               /* During the device boot-up, calculate energy for 100% battery and calcuate
+               pivot(norma and UPS mode) for time remaining time estimation*/
+               heart_battery_calculate_pivot();
+               /*get all the previousely stored data from file to program variable*/
+               heart_battery_read_data_from_file();
+               /*
+               * check whether was device power off for long time. If yes then adjust
+               * our stored time values
+               */
+               heart_battery_power_off_time_adjustment();
+               /*
+               * register callback for any time change from user side.
+               * If any time change happen then adjust whole data as per new time
+               */
+               vconf_notify_key_changed(VCONFKEY_SETAPPL_TIMEZONE_INT, time_change_notify_cb, NULL);
+               vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, time_change_notify_cb, NULL);
+               vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, time_change_notify_cb, NULL);
+       }
+
        battery_learning_mode = heart_battery_get_learning_mode();
 
        ret = heart_battery_capacity_read_from_file(HEART_BATTERY_CAPACITY_DATA_FILE);
        if (ret < 0)
                _E("Failed to read battery capacity data");
 
-       capacity = heart_battery_get_capacity();
+       capacity = heart_battery_direct_get_capacity();
        if (capacity > 0)
                batt_stat.curr_capacity = capacity;
-       status = heart_battery_get_charger_status();
+       status = heart_battery_direct_get_charger_status();
        if (status >= 0)
                batt_stat.curr_charger_status = status;
        heart_battery_used_time_init(batt_stat.curr_charger_status);
        heart_battery_calculate_prediction(batt_stat.curr_charger_status);
        batt_stat.last_event_wall_time = logging_get_time(CLOCK_BOOTTIME);
+       batt_stat.discharge_rate_level = BATTERY_DISCHARGE_NONE;
+
+       if (logic_v2) {
+               heart_battery_cal_discharge_rem_time();
+
+               if (batt_stat.curr_charger_status == CHARGING) {
+                       heart_battery_cal_charging_rem_time();
+                       first_level_change = TRUE;
+               }
+       }
 }
 
 static int low_battery_handler(void *data)
@@ -1915,24 +2742,56 @@ static int heart_battery_config(struct parse_result *result, void *user_data)
        if (!result)
                return -EINVAL;
 
-       if (strncmp(result->section, HEART_BATTERY_CONF_SECTION, strlen(HEART_BATTERY_CONF_SECTION)+1))
-               return RESOURCED_ERROR_NONE;
-
-       if (!strncmp(result->name, "POWER_NORMAL_MODE", strlen("POWER_NORMAL_MODE")+1)) {
-               val = atoi(result->value);
-               if (val > 0)
-                       default_mode_spc[POWER_NORMAL_MODE] = val;
-               _D("POWER_NORMAL_MODE SPC: %d", val);
-       } else if (!strncmp(result->name, "POWER_SAVING_MODE", strlen("POWER_SAVING_MODE")+1)) {
-               val = atoi(result->value);
-               if (val > 0)
-                       default_mode_spc[POWER_SAVING_MODE] = val;
-               _D("POWER_SAVING_MODE SPC: %d", val);
-       } else if (!strncmp(result->name, "ULTRA_SAVING_MODE", strlen("ULTRA_SAVING_MODE")+1)) {
-               val = atoi(result->value);
-               if (val > 0)
-                       default_mode_spc[ULTRA_SAVING_MODE] = val;
-               _D("ULTRA_POWER_SAVING_MODE SPC: %d", val);
+       if (!strncmp(result->section, HEART_BATTERY_CONF_SECTION, sizeof(HEART_BATTERY_CONF_SECTION) + 1)) {
+               if (!strncmp(result->name, "POWER_NORMAL_MODE", sizeof("POWER_NORMAL_MODE") + 1)) {
+                       val = atoi(result->value);
+                       if (val > 0)
+                               default_mode_spc[POWER_NORMAL_MODE] = val;
+                       _D("POWER_NORMAL_MODE SPC: %d", val);
+               } else if (!strncmp(result->name, "POWER_SAVING_MODE", sizeof("POWER_SAVING_MODE") + 1)) {
+                       val = atoi(result->value);
+                       if (val > 0)
+                               default_mode_spc[POWER_SAVING_MODE] = val;
+                       _D("POWER_SAVING_MODE SPC: %d", val);
+               } else if (!strncmp(result->name, "ULTRA_SAVING_MODE", sizeof("ULTRA_SAVING_MODE") + 1)) {
+                       val = atoi(result->value);
+                       if (val > 0)
+                               default_mode_spc[ULTRA_SAVING_MODE] = val;
+                       _D("ULTRA_POWER_SAVING_MODE SPC: %d", val);
+               }
+       } else if (!strncmp(result->section, battery_header, sizeof(battery_header) + 1)) {
+               if (!strncmp(result->name, "LOGIC_V2", sizeof("LOGIC_V2") + 1)) {
+                       logic_v2 = atoi(result->value);
+                       _I("logic_v2 : %d", logic_v2);
+               } else if (!strncmp(result->name, "DISCHARGE_FAST", sizeof("DISCHARGE_FAST") + 1)) {
+                       discharge_fast = atoi(result->value);
+                       _I("discharge_fast: %d", discharge_fast);
+               } else if (!strncmp(result->name, "DISCHARGE_SLOW", sizeof("DISCHARGE_SLOW") + 1)) {
+                       discharge_slow = atoi(result->value);
+                       _I("discharge_slow: %d", discharge_slow);
+               } else if (!strncmp(result->name, "AVERAGE_PWR", sizeof("AVERAGE_PWR") + 1)) {
+                       average_pwr = atof(result->value);
+                       _I("average_power: %lf", average_pwr);
+               } else if (!strncmp(result->name, "OCV_SOC_POLY_COEF", sizeof("OCV_SOC_POLY_COEF") + 1)) {
+                       char *token, *saveptr;
+                       int i;
+                       token = strtok_r(result->value, " ", &saveptr);
+                       if (token) {
+                               ocv_degree = atoi(token);
+                               intg = calloc(ocv_degree, sizeof(double));
+                               if (!intg) {
+                                       _E("Out of memory");
+                                       return -ENOMEM;
+                               }
+                               _I("Degree of OCV_SOC_POLY = %d", ocv_degree);
+
+                               for (i = 1; i <= ocv_degree ; i++) {
+                                       token = strtok_r(NULL, " ", &saveptr);
+                                       intg[i] = atof(token);
+                                       _I("OCV_SOC_POLY_COEF_%d = %.9g", i, intg[i]);
+                               }
+                       }
+               }
        }
        return RESOURCED_ERROR_NONE;
 }
@@ -1954,11 +2813,42 @@ static void heart_battery_mode_factor_init(void)
        _I("ULTRA_POWER_SAVING_MODE factor: %f", val);
 }
 
+/*
+ * This function will read total battery capacity from sys interface
+ * example - 1500mAh or 2600mAh
+ */
+static void heart_read_battery_total_capacity(void)
+{
+       u_int32_t batt_capacity;
+
+       /*
+        * read the battery total capacity from sys interface path
+        * "/sys/class/power_supply/battery/batt_capacity"
+        * which is provided by kernel
+        */
+       if (fread_uint("/sys/class/power_supply/battery/batt_capacity",
+                                       &batt_capacity) != RESOURCED_ERROR_NONE) {
+               _D("This device doesn't support battery capacity information. Disable LOGIC_V2");
+               return;
+       }
+
+       snprintf(battery_header, sizeof(battery_header), "BATTERY_%d",
+                       batt_capacity);
+
+       /*
+        * convert battery capacity from mAh to mAm
+        */
+       total_battery_capacity = batt_capacity * 60;
+       _I("battery capacity = %d, battery header = %s",
+                       batt_capacity, battery_header);
+}
+
 static int heart_battery_init(void *data)
 {
        int ret;
 
-       ret = logging_module_init(BATTERY_NAME, ONE_DAY, TEN_MINUTE, heart_battery_update, HEART_BATTERY_UPDATE_INTERVAL, SYSTEM_DEFAULT);
+       ret = logging_module_init(BATTERY_NAME, ONE_DAY, TEN_MINUTE, heart_battery_update,
+                                                       HEART_BATTERY_UPDATE_INTERVAL, SYSTEM_DEFAULT);
        if (ret != RESOURCED_ERROR_NONE) {
                _E("logging module init failed");
                return RESOURCED_ERROR_FAIL;
@@ -1982,6 +2872,8 @@ static int heart_battery_init(void *data)
        if (ret < 0)
                _E("Failed to add a charger status signal handler");
 
+       heart_read_battery_total_capacity();
+
        config_parse(HEART_CONF_FILE_PATH, heart_battery_config, NULL);
 
        heart_battery_mode_factor_init();
index f1468fe..93a78e0 100644 (file)
@@ -8,3 +8,25 @@ APPOPT=OFF
 POWER_NORMAL_MODE=676
 POWER_SAVING_MODE=750
 ULTRA_SAVING_MODE=1947
+
+# OCV_SOC_POLY_COEF=(DEGREE) (COEF_1) ... (COEF_N)
+
+[BATTERY_2600]
+LOGIC_V2=1
+DISCHARGE_FAST=700
+DISCHARGE_SLOW=12000
+AVERAGE_PWR=35.0
+OCV_SOC_POLY_COEF=6 3402.664 42.031 -1.76745 0.034798 -0.00030516 0.0000010116
+
+[BATTERY_1500]
+LOGIC_V2=1
+DISCHARGE_FAST=200
+DISCHARGE_SLOW=7000
+AVERAGE_PWR=35.0
+OCV_SOC_POLY_COEF=6 3402.664 42.031 -1.76745 0.034798 -0.00030516 0.0000010116
+
+[BATTERY]
+LOGIC_V2=0
+DISCHARGE_FAST=0
+DISCHARGE_SLOW=0
+AVERAGE_PWR=0.0