Use milisec unit instead of sec for power duration
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / bt-service-battery-monitor.c
index 908c551..ce452ed 100644 (file)
 #include <string.h>
 #include <dlog.h>
 #include <time.h>
-
+#include <sys/time.h>
 
 #include <oal-event.h>
 
 #include "bt-service-battery-monitor.h"
 #include "bt-service-common.h"
+#include "bt-service-event.h"
+#include "bt-service-core-adapter.h"
 
-static time_t scan_start = 0;
-static time_t connect_start = 0;
+static struct timeval scan_start;
+static struct timeval connect_start;
+static struct timeval app_scan_base;
 static int scan_cnt = 0;
 static int connect_cnt = 0;
 static gboolean is_session_started = FALSE;
 
+static GSList *scan_app_list = NULL;
+
 typedef struct {
         int type;
         void *data;
@@ -44,6 +49,13 @@ typedef struct {
 
 _bt_battery_data_t *current_session_data = NULL;
 
+static void __bt_bm_add_prev_time(uint32_t scan_time);
+
+uint32_t static __bt_dm_time_diff_msec(struct timeval prev, struct timeval cur)
+{
+    return (uint32_t)((cur.tv_sec - prev.tv_sec) * 1000.0f + (cur.tv_usec - prev.tv_usec) / 1000.0f);
+}
+
 static void __bt_display_session_data()
 {
        BT_DBG("Displaying session data...");
@@ -56,6 +68,14 @@ static void __bt_display_session_data()
 /*After reading data, the function resets it*/
 int _bt_bm_read_data(_bt_battery_data_t *data)
 {
+       struct timeval cur_time;
+       uint32_t tx_time = 0;
+       uint32_t rx_time = 0;
+       uint32_t idle_time = 0;
+       uint32_t energy_used = 0;
+       uint16_t scan_time_per_app = 0;
+       int scan_app_cnt = 0;
+
        BT_DBG("");
 
        if (data == NULL) {
@@ -63,6 +83,18 @@ int _bt_bm_read_data(_bt_battery_data_t *data)
                return BLUETOOTH_ERROR_NO_DATA;
        }
 
+       if (_bt_get_energy_info(&tx_time, &rx_time,
+                               &idle_time, &energy_used) != BLUETOOTH_ERROR_NONE) {
+               BT_ERR("Fail to get energy info");
+               return BLUETOOTH_ERROR_NOT_SUPPORT;
+       }
+
+       gettimeofday(&cur_time, 0);
+
+       data->tx_time = tx_time;
+       data->rx_time = rx_time;
+       data->idle_time = idle_time;
+
        data->session_start_time = current_session_data->session_start_time;
        data->session_end_time = time(NULL);
        current_session_data->session_start_time = time(NULL);
@@ -70,16 +102,27 @@ int _bt_bm_read_data(_bt_battery_data_t *data)
 
        data->session_scan_time = current_session_data->session_scan_time;
        if (scan_cnt) {
-               data->session_scan_time += (uint16_t) (time(NULL) - scan_start);
-               scan_start = time(NULL);
+               data->session_scan_time += (uint16_t)__bt_dm_time_diff_msec(scan_start, cur_time);
+               gettimeofday(&scan_start, 0);
        }
+       current_session_data->session_scan_time = 0;
 
        data->session_connected_time = current_session_data->session_connected_time;
        if (connect_cnt) {
-               data->session_connected_time += (uint16_t) (time(NULL) - connect_start);
-               connect_start = time(NULL);
+               data->session_connected_time += (uint16_t)__bt_dm_time_diff_msec(connect_start, cur_time);
+               gettimeofday(&connect_start, 0);
+       }
+       current_session_data->session_connected_time = 0;
+
+       scan_app_cnt = g_slist_length(scan_app_list);
+
+       if (scan_app_cnt > 0) {
+               scan_time_per_app = (uint32_t)__bt_dm_time_diff_msec(app_scan_base, cur_time) / scan_app_cnt;
+               __bt_bm_add_prev_time(scan_time_per_app);
        }
 
+       gettimeofday(&app_scan_base, 0);
+
        data->atm_list = current_session_data->atm_list;
        if (data->atm_list == NULL) {
                BT_DBG("No data transaction in this session");
@@ -89,7 +132,7 @@ int _bt_bm_read_data(_bt_battery_data_t *data)
        BT_DBG("App-wise data transaction details");
        for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
                _bt_battery_app_data_t *t = (_bt_battery_app_data_t *)(l->data);
-               BT_DBG("%ld %ld %d %d", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes);
+               BT_DBG("%ld %ld %d %d %u", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes, t->time);
        }
 
        current_session_data->atm_list = NULL;
@@ -111,7 +154,7 @@ static GSList* is_app_present(GSList *start, uid_t uid, pid_t pid)
        return NULL;
 }
 
-void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int size, data_transaction_type_e type)
+void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int value, data_transaction_type_e type)
 {
        if (current_session_data == NULL) {
                BT_ERR("Session in progress but data structure is not initialized"); //error handling
@@ -126,18 +169,22 @@ void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int size, data_transac
                app_data->uid = uid;
                app_data->pid = pid;
                if (type == RX_DATA)
-                       app_data->rx_bytes = size;
+                       app_data->rx_bytes = value;
+               else if (type == TX_DATA)
+                       app_data->tx_bytes = value;
                else
-                       app_data->tx_bytes = size;
+                       app_data->time = value;
                current_session_data->atm_list = g_slist_append(current_session_data->atm_list, app_data);
        }
        else {
                BT_INFO("Match found, updating existing node...");
                app_data = (_bt_battery_app_data_t *)(t->data);
                if (type == RX_DATA)
-                       app_data->rx_bytes += size;
+                       app_data->rx_bytes += value;
+               else if (type == TX_DATA)
+                       app_data->tx_bytes += value;
                else
-                       app_data->tx_bytes += size;
+                       app_data->time += value;
        }
 }
 
@@ -172,12 +219,152 @@ void _bt_stop_session_time()
        __bt_display_session_data();
 }
 
+/* 1 app can operate the regacy and ble scan at the same time */
+static GSList* __is_scan_app_present(GSList *start, bt_bm_scan_type_e type, uid_t uid, pid_t pid)
+{
+       GSList *l = NULL;
+       bt_bm_scan_info_t *t;
+
+       for (l = start; l != NULL; l = g_slist_next(l)) {
+               t = (bt_bm_scan_info_t *)(l->data);
+
+               /* Find the regacy scan app for Inquiry stop */
+               if (type == SCAN_REGACY && t->type != SCAN_LE) {
+                       BT_INFO("app already exist");
+                       return l;
+               }
+
+               if (t->uid == uid && t->pid == pid) {
+                       BT_INFO("app already exist");
+                       return l;
+               }
+       }
+       return NULL;
+}
+
+static void __bt_bm_add_prev_time(uint32_t scan_time)
+{
+       GSList *l = NULL;
+       bt_bm_scan_info_t *t;
+
+       for (l = scan_app_list; l != NULL; l = g_slist_next(l)) {
+               t = (bt_bm_scan_info_t *)(l->data);
+               _bt_bm_add_transaction_details(t->uid, t->pid, scan_time, TIME_DATA);
+       }
+}
+
+/* 1 regacy scan is only allowed in the platform
+ * BLE scan is allowed for many apps
+*/
+/* When a app is added, we should add and reset the time. */
+void _bt_bm_add_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
+{
+       bt_bm_scan_info_t *scan_info = NULL;
+       GSList *app_list = NULL;
+       int app_cnt = 0;
+       uint32_t scan_time_per_app = 0;
+
+       BT_DBG("Scan type: %d", type);
+
+       if (scan_app_list) {
+               app_cnt = g_slist_length(scan_app_list);
+               app_list = __is_scan_app_present(scan_app_list, SCAN_BOTH, uid, pid);
+       }
+
+       if (app_list) {
+               /* app try to scan both Regacy and LE */
+               scan_info = (bt_bm_scan_info_t *)(app_list->data);
+
+               if (scan_info == NULL) {
+                       BT_ERR("Can't get the scan info");
+                       return;
+               }
+
+               BT_DBG("Previous type: %d", scan_info->type);
+
+               if (scan_info->type == type) {
+                       BT_ERR("Same scan type is doing");
+                       return;
+               }
+
+               scan_info->type = SCAN_BOTH;
+       } else {
+               scan_info = g_malloc0(sizeof(bt_bm_scan_info_t));
+               scan_info->uid = uid;
+               scan_info->pid = pid;
+               scan_info->type = type;
+
+               if (app_cnt > 0) {
+                       struct timeval cur_time;
+
+                       gettimeofday(&cur_time, 0);
+
+                       scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
+                       __bt_bm_add_prev_time(scan_time_per_app);
+
+                       /* Update the base time */
+                       gettimeofday(&app_scan_base, 0);
+               }
+
+               scan_app_list = g_slist_append(scan_app_list, scan_info);
+       }
+}
+
+/* When a app is removed, we should add and reset the time. */
+void _bt_bm_remove_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
+{
+       bt_bm_scan_info_t *scan_info = NULL;
+       GSList *app_list = NULL;
+       int app_cnt = 0;
+       uint32_t scan_time_per_app = 0;
+
+       BT_DBG("Scan type: %d", type);
+
+       if (scan_app_list == NULL) {
+               BT_ERR("No scan app in list");
+               return;
+       }
+
+       app_cnt = g_slist_length(scan_app_list);
+
+       if (app_cnt == 0) {
+               BT_ERR("No scan app in list");
+               return;
+       }
+
+       app_list = __is_scan_app_present(scan_app_list, type, uid, pid);
+
+       if (app_list) {
+               struct timeval cur_time;
+
+               scan_info = (bt_bm_scan_info_t *)(app_list->data);
+
+               if (scan_info->type == SCAN_BOTH) {
+                       scan_info->type = (scan_info->type == SCAN_REGACY) ? SCAN_LE : SCAN_REGACY;
+                       return;
+               }
+
+               gettimeofday(&cur_time, 0);
+
+               scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
+               __bt_bm_add_prev_time(scan_time_per_app);
+
+               /* Update the base time */
+               gettimeofday(&app_scan_base, 0);
+
+               scan_app_list = g_slist_remove(scan_app_list, scan_info);
+
+               g_free(scan_info);
+       }
+}
+
 void _bt_start_scan_time()
 {
        if (current_session_data != NULL) {
                if (scan_cnt == 0) {
                        BT_DBG("Starting scan time");
-                       scan_start = time(NULL);
+                       gettimeofday(&scan_start, 0);
+                       gettimeofday(&app_scan_base, 0);
                }
                scan_cnt++;
        } else {
@@ -192,8 +379,12 @@ void _bt_stop_scan_time()
        else {
                scan_cnt--;
                if(scan_cnt == 0) {
-                       time_t temp = time(NULL);
-                       current_session_data->session_scan_time += (uint16_t) (temp - scan_start);
+                       struct timeval cur_time;
+
+                       gettimeofday(&cur_time, 0);
+                       current_session_data->session_scan_time += (uint16_t)(__bt_dm_time_diff_msec(scan_start, cur_time));
+                       gettimeofday(&scan_start, 0);
+                       gettimeofday(&app_scan_base, 0);
                }
        }
 }
@@ -203,7 +394,7 @@ void _bt_start_connect_time()
        if (current_session_data != NULL) {
                if (connect_cnt == 0) {
                        BT_DBG("Starting connect time");
-                       connect_start = time(NULL);
+                       gettimeofday(&connect_start, 0);
                }
                connect_cnt++;
        }
@@ -220,10 +411,64 @@ void _bt_stop_connect_time()
        else {
                connect_cnt--;
                if(connect_cnt == 0) {
-                       time_t temp = time(NULL);
-                       current_session_data->session_connected_time += (uint16_t) (temp - connect_start);
+                       struct timeval cur_time;
+
+                       gettimeofday(&cur_time, 0);
+                       current_session_data->session_connected_time += (uint16_t)(__bt_dm_time_diff_msec(connect_start, cur_time));
+               }
+       }
+}
+
+static void _bt_notify_battery_data(void)
+{
+       BT_INFO("+");
+       _bt_battery_data_t *data = NULL;
+       int result;
+
+       data = g_new0(_bt_battery_data_t, 1);
+       result = _bt_bm_read_data(data);
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (result != BLUETOOTH_ERROR_NONE) {
+               BT_ERR("Battery data not collected");
+       }
+       else {
+               bt_battery_dbus_data_t dbus_data;
+               memset(&dbus_data, 0, sizeof(bt_battery_dbus_data_t));
+               dbus_data.session_start_time = data->session_start_time;
+               dbus_data.session_end_time = data->session_end_time;
+               dbus_data.session_scan_time = data->session_scan_time;
+               dbus_data.session_connected_time = data->session_connected_time;
+               dbus_data.tx_time = data->tx_time;
+               dbus_data.rx_time = data->rx_time;
+               dbus_data.idle_time = data->idle_time;
+
+               /*Populating app data*/
+               int n = 0;
+               for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
+                       bt_battery_app_data *t = (bt_battery_app_data *)(l->data);
+                       memcpy(&dbus_data.app_data[n], t, sizeof(bt_battery_app_data));
+                       n++;
                }
+               dbus_data.num_app = n;
+
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &dbus_data, sizeof(bt_battery_dbus_data_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
        }
+       param = g_variant_new("(iv)", result, out_var);
+       _bt_send_event(BT_ADAPTER_EVENT,
+               BLUETOOTH_EVENT_DISABLED_BATTERY_DATA,
+               param);
+
+       g_slist_free(data->atm_list);
+       g_free(data);
+       g_array_free(info, TRUE);
+       BT_INFO("-");
 }
 
 void _bt_bm_event_handler(gpointer data)
@@ -239,6 +484,7 @@ void _bt_bm_event_handler(gpointer data)
        case OAL_EVENT_ADAPTER_DISABLED:
                BT_DBG("Handling Adapter Disabled");
                _bt_stop_session_time();
+               _bt_notify_battery_data();
                break;
        case OAL_EVENT_ADAPTER_INQUIRY_STARTED:
        case OAL_EVENT_BLE_DISCOVERY_STARTED:
@@ -246,6 +492,11 @@ void _bt_bm_event_handler(gpointer data)
                _bt_start_scan_time();
                break;
        case OAL_EVENT_ADAPTER_INQUIRY_FINISHED:
+               /* Remove the regacy scan app */
+               _bt_bm_remove_scan_app(SCAN_REGACY, 0, 0);
+
+               _bt_stop_scan_time();
+               break;
        case OAL_EVENT_BLE_DISCOVERY_STOPPED:
                BT_DBG("Handling Adapter Discovery Stop");
                _bt_stop_scan_time();