4 * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Sudipto Bal <sudipto.bal@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
30 #include <oal-event.h>
32 #include "bt-service-battery-monitor.h"
33 #include "bt-service-common.h"
34 #include "bt-service-event.h"
35 #include "bt-service-core-adapter.h"
37 /* Avoid the build error related to vconf.h's dependency */
38 #ifndef VCONFKEY_BATTERY_MONITOR_STATUS
39 #define VCONFKEY_BATTERY_MONITOR_STATUS "db/bluetooth/bmstatus"
42 static struct timeval scan_start;
43 static struct timeval connect_start;
44 static struct timeval app_scan_base;
45 static int scan_cnt = 0;
46 static int connect_cnt = 0;
47 static gboolean is_session_started = FALSE;
49 static GSList *scan_app_list = NULL;
54 } bt_service_oal_event_data_t;
56 _bt_battery_data_t *current_session_data = NULL;
58 static void __bt_bm_add_prev_time(uint32_t scan_time);
59 static int __bt_start_session_time(void);
61 uint32_t static __bt_dm_time_diff_msec(struct timeval prev, struct timeval cur)
63 return (uint32_t)((cur.tv_sec - prev.tv_sec) * 1000.0f + (cur.tv_usec - prev.tv_usec) / 1000.0f);
66 static void __bt_display_session_data()
68 BT_DBG("Displaying session data...");
70 if (current_session_data == NULL) {
71 BT_ERR("Session in progress but data structure is not initialized");
75 BT_DBG("session_start_time = %ld", current_session_data->session_start_time);
76 BT_DBG("session_end_time = %ld", current_session_data->session_end_time);
77 BT_DBG("session_scan_time = %d", current_session_data->session_scan_time);
78 BT_DBG("session_connected_time = %d", current_session_data->session_connected_time);
81 /*After reading data, the function resets it*/
82 int _bt_bm_read_data(_bt_battery_data_t *data)
84 struct timeval cur_time;
87 uint32_t idle_time = 0;
88 uint32_t energy_used = 0;
89 uint16_t scan_time_per_app = 0;
95 BT_ERR("Received NULL pointer in argument, returning...");
96 return BLUETOOTH_ERROR_NO_DATA;
99 if (_bt_get_energy_info(&tx_time, &rx_time,
100 &idle_time, &energy_used) != BLUETOOTH_ERROR_NONE) {
101 BT_ERR("Fail to get energy info");
102 return BLUETOOTH_ERROR_NOT_SUPPORT;
105 if (is_session_started == FALSE) {
106 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
107 BT_ERR("Fail to start session time");
108 return BLUETOOTH_ERROR_NOT_SUPPORT;
112 if (current_session_data == NULL) {
113 BT_ERR("Session in progress but data structure is not initialized");
114 return BLUETOOTH_ERROR_INTERNAL;
117 gettimeofday(&cur_time, 0);
119 data->tx_time = tx_time;
120 data->rx_time = rx_time;
121 data->idle_time = idle_time;
123 data->session_start_time = current_session_data->session_start_time;
124 data->session_end_time = time(NULL);
125 current_session_data->session_start_time = time(NULL);
126 current_session_data->session_end_time = 0;
128 data->session_scan_time = current_session_data->session_scan_time;
130 data->session_scan_time += (uint16_t)__bt_dm_time_diff_msec(scan_start, cur_time);
131 gettimeofday(&scan_start, 0);
133 current_session_data->session_scan_time = 0;
135 data->session_connected_time = current_session_data->session_connected_time;
137 data->session_connected_time += (uint16_t)__bt_dm_time_diff_msec(connect_start, cur_time);
138 gettimeofday(&connect_start, 0);
140 current_session_data->session_connected_time = 0;
142 scan_app_cnt = g_slist_length(scan_app_list);
144 if (scan_app_cnt > 0) {
145 scan_time_per_app = (uint32_t)__bt_dm_time_diff_msec(app_scan_base, cur_time) / scan_app_cnt;
146 __bt_bm_add_prev_time(scan_time_per_app);
149 gettimeofday(&app_scan_base, 0);
151 data->atm_list = current_session_data->atm_list;
152 if (data->atm_list == NULL) {
153 BT_DBG("No data transaction in this session");
154 return BLUETOOTH_ERROR_NONE;
157 BT_DBG("App-wise data transaction details");
158 for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
159 _bt_battery_app_data_t *t = (_bt_battery_app_data_t *)(l->data);
160 BT_DBG("%ld %ld %d %d %u", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes, t->time);
163 current_session_data->atm_list = NULL;
164 return BLUETOOTH_ERROR_NONE;
167 static GSList* is_app_present(GSList *start, uid_t uid, pid_t pid)
170 _bt_battery_app_data_t *t;
171 BT_INFO("Checking Memory location %p", start);
172 for (l=start; l != NULL; l = g_slist_next(l)) {
173 t = (_bt_battery_app_data_t *)(l->data);
174 if (t->uid == uid && t->pid == pid) {
175 BT_INFO("App details already exist");
182 void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int value, data_transaction_type_e type)
184 if (is_session_started == FALSE)
185 __bt_start_session_time();
187 if (current_session_data == NULL) {
188 BT_ERR("Session in progress but data structure is not initialized");
191 GSList *t = is_app_present(current_session_data->atm_list, uid, pid);
192 _bt_battery_app_data_t *app_data = NULL;
195 BT_INFO("Match not found, adding new node...");
196 app_data = g_malloc0(sizeof(_bt_battery_app_data_t));
200 app_data->rx_bytes = value;
201 else if (type == TX_DATA)
202 app_data->tx_bytes = value;
204 app_data->time = value;
205 current_session_data->atm_list = g_slist_append(current_session_data->atm_list, app_data);
208 BT_INFO("Match found, updating existing node...");
209 app_data = (_bt_battery_app_data_t *)(t->data);
211 app_data->rx_bytes += value;
212 else if (type == TX_DATA)
213 app_data->tx_bytes += value;
215 app_data->time += value;
219 static int __bt_start_session_time(void)
223 if (is_session_started == TRUE) {
224 BT_ERR("Session is already started");
225 return BLUETOOTH_ERROR_ALREADY_INITIALIZED;
228 if (vconf_get_bool(VCONFKEY_BATTERY_MONITOR_STATUS, &state) != 0) {
229 BT_ERR("vconf_get_bool failed");
230 return BLUETOOTH_ERROR_INTERNAL;
234 BT_ERR("Battery is not monitoring in now");
235 return BLUETOOTH_ERROR_NOT_SUPPORT;
238 BT_DBG("Bt session starting...");
239 is_session_started = TRUE;
241 if (current_session_data == NULL)
242 current_session_data = g_malloc0(sizeof(_bt_battery_data_t));
244 current_session_data->session_start_time = time(NULL);
245 current_session_data->session_end_time = 0;
246 current_session_data->session_connected_time = 0;
247 current_session_data->session_scan_time = 0;
248 current_session_data->atm_list = NULL;
250 return BLUETOOTH_ERROR_NONE;
253 void _bt_stop_session_time(void)
255 if (is_session_started == FALSE) {
256 BT_DBG("BT session not in progress... Returning");
260 BT_DBG("Bt session ending...");
261 is_session_started = FALSE;
263 if (current_session_data == NULL) {
264 BT_ERR("Session in progress but data structure is not initialized");
268 current_session_data->session_end_time = time(NULL);
269 __bt_display_session_data();
272 /* 1 app can operate the regacy and ble scan at the same time */
273 static GSList* __is_scan_app_present(GSList *start, bt_bm_scan_type_e type, uid_t uid, pid_t pid)
276 bt_bm_scan_info_t *t;
278 for (l = start; l != NULL; l = g_slist_next(l)) {
279 t = (bt_bm_scan_info_t *)(l->data);
281 /* Find the regacy scan app for Inquiry stop */
282 if (type == SCAN_REGACY && t->type != SCAN_LE) {
283 BT_INFO("app already exist");
287 if (t->uid == uid && t->pid == pid) {
288 BT_INFO("app already exist");
295 static void __bt_bm_add_prev_time(uint32_t scan_time)
298 bt_bm_scan_info_t *t;
300 for (l = scan_app_list; l != NULL; l = g_slist_next(l)) {
301 t = (bt_bm_scan_info_t *)(l->data);
302 _bt_bm_add_transaction_details(t->uid, t->pid, scan_time, TIME_DATA);
306 /* 1 regacy scan is only allowed in the platform
307 * BLE scan is allowed for many apps
309 /* When a app is added, we should add and reset the time. */
310 void _bt_bm_add_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
312 bt_bm_scan_info_t *scan_info = NULL;
313 GSList *app_list = NULL;
315 uint32_t scan_time_per_app = 0;
317 BT_DBG("Scan type: %d", type);
320 app_cnt = g_slist_length(scan_app_list);
321 app_list = __is_scan_app_present(scan_app_list, SCAN_BOTH, uid, pid);
325 /* app try to scan both Regacy and LE */
326 scan_info = (bt_bm_scan_info_t *)(app_list->data);
328 if (scan_info == NULL) {
329 BT_ERR("Can't get the scan info");
333 BT_DBG("Previous type: %d", scan_info->type);
335 if (scan_info->type == type) {
336 BT_ERR("Same scan type is doing");
340 scan_info->type = SCAN_BOTH;
342 scan_info = g_malloc0(sizeof(bt_bm_scan_info_t));
343 scan_info->uid = uid;
344 scan_info->pid = pid;
345 scan_info->type = type;
348 struct timeval cur_time;
350 gettimeofday(&cur_time, 0);
352 scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
353 __bt_bm_add_prev_time(scan_time_per_app);
355 /* Update the base time */
356 gettimeofday(&app_scan_base, 0);
359 scan_app_list = g_slist_append(scan_app_list, scan_info);
363 /* When a app is removed, we should add and reset the time. */
364 void _bt_bm_remove_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
366 bt_bm_scan_info_t *scan_info = NULL;
367 GSList *app_list = NULL;
369 uint32_t scan_time_per_app = 0;
371 BT_DBG("Scan type: %d", type);
373 if (scan_app_list == NULL) {
374 BT_ERR("No scan app in list");
378 app_cnt = g_slist_length(scan_app_list);
381 BT_ERR("No scan app in list");
385 app_list = __is_scan_app_present(scan_app_list, type, uid, pid);
388 struct timeval cur_time;
390 scan_info = (bt_bm_scan_info_t *)(app_list->data);
392 if (scan_info->type == SCAN_BOTH) {
393 scan_info->type = (scan_info->type == SCAN_REGACY) ? SCAN_LE : SCAN_REGACY;
397 gettimeofday(&cur_time, 0);
399 scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
400 __bt_bm_add_prev_time(scan_time_per_app);
402 /* Update the base time */
403 gettimeofday(&app_scan_base, 0);
405 scan_app_list = g_slist_remove(scan_app_list, scan_info);
411 void _bt_start_scan_time()
413 if (is_session_started == FALSE) {
414 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
415 BT_ERR("Fail to start session time");
420 if (current_session_data != NULL) {
422 BT_DBG("Starting scan time");
423 gettimeofday(&scan_start, 0);
424 gettimeofday(&app_scan_base, 0);
428 BT_ERR("Data structure uninitialized");
432 void _bt_stop_scan_time()
434 if (is_session_started == FALSE) {
435 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
436 BT_ERR("Fail to start session time");
441 if (scan_cnt == 0 || current_session_data == NULL)
442 BT_ERR("Error encountered, returning...");
446 struct timeval cur_time;
448 gettimeofday(&cur_time, 0);
449 current_session_data->session_scan_time += (uint16_t)(__bt_dm_time_diff_msec(scan_start, cur_time));
450 gettimeofday(&scan_start, 0);
451 gettimeofday(&app_scan_base, 0);
456 void _bt_start_connect_time()
458 if (is_session_started == FALSE) {
459 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
460 BT_ERR("Fail to start session time");
465 if (current_session_data != NULL) {
466 if (connect_cnt == 0) {
467 BT_DBG("Starting connect time");
468 gettimeofday(&connect_start, 0);
473 BT_ERR("Data structure uninitialized");
477 void _bt_stop_connect_time()
479 if (is_session_started == FALSE) {
480 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
481 BT_ERR("Fail to start session time");
486 if(connect_cnt == 0 || current_session_data == NULL) {
487 BT_ERR("Error encountered, returning...");
490 if(connect_cnt == 0) {
491 struct timeval cur_time;
493 gettimeofday(&cur_time, 0);
494 current_session_data->session_connected_time += (uint16_t)(__bt_dm_time_diff_msec(connect_start, cur_time));
499 static void __bt_notify_battery_data(void)
502 _bt_battery_data_t *data = NULL;
505 data = g_new0(_bt_battery_data_t, 1);
506 result = _bt_bm_read_data(data);
507 GVariant *out_var = NULL, *param = NULL;
510 if (result != BLUETOOTH_ERROR_NONE) {
511 BT_ERR("Battery data not collected");
514 bt_battery_dbus_data_t dbus_data;
515 memset(&dbus_data, 0, sizeof(bt_battery_dbus_data_t));
516 dbus_data.session_start_time = data->session_start_time;
517 dbus_data.session_end_time = data->session_end_time;
518 dbus_data.session_scan_time = data->session_scan_time;
519 dbus_data.session_connected_time = data->session_connected_time;
520 dbus_data.tx_time = data->tx_time;
521 dbus_data.rx_time = data->rx_time;
522 dbus_data.idle_time = data->idle_time;
524 /*Populating app data*/
526 for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
527 bt_battery_app_data *t = (bt_battery_app_data *)(l->data);
528 memcpy(&dbus_data.app_data[n], t, sizeof(bt_battery_app_data));
531 dbus_data.num_app = n;
533 info = g_array_new(FALSE, FALSE, sizeof(gchar));
534 g_array_append_vals(info, &dbus_data, sizeof(bt_battery_dbus_data_t));
536 out_var = g_variant_new_from_data((const GVariantType *)"ay",
537 info->data, info->len,
540 param = g_variant_new("(iv)", result, out_var);
541 _bt_send_event(BT_ADAPTER_EVENT,
542 BLUETOOTH_EVENT_DISABLED_BATTERY_DATA,
545 g_slist_free(data->atm_list);
547 g_array_free(info, TRUE);
551 void _bt_bm_event_handler(gpointer data)
553 bt_service_oal_event_data_t *oal_event = data;
554 int event_type = oal_event->type;
557 case OAL_EVENT_ADAPTER_ENABLED:
558 BT_DBG("Handling Adapter Enabled");
559 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE)
560 BT_ERR("Fail to start session time");
562 case OAL_EVENT_ADAPTER_DISABLED:
563 BT_DBG("Handling Adapter Disabled");
564 if (is_session_started == TRUE) {
565 _bt_stop_session_time();
566 __bt_notify_battery_data();
569 case OAL_EVENT_ADAPTER_INQUIRY_STARTED:
570 case OAL_EVENT_BLE_DISCOVERY_STARTED:
571 BT_DBG("Handling Adapter Discovery Start");
572 _bt_start_scan_time();
574 case OAL_EVENT_ADAPTER_INQUIRY_FINISHED:
575 /* Remove the regacy scan app */
576 _bt_bm_remove_scan_app(SCAN_REGACY, 0, 0);
578 _bt_stop_scan_time();
580 case OAL_EVENT_BLE_DISCOVERY_STOPPED:
581 BT_DBG("Handling Adapter Discovery Stop");
582 _bt_stop_scan_time();
584 case OAL_EVENT_SOCKET_OUTGOING_CONNECTED:
585 case OAL_EVENT_GATTC_CONNECTION_COMPLETED:
586 BT_DBG("Handling Connection Start");
587 _bt_start_connect_time();
589 case OAL_EVENT_SOCKET_DISCONNECTED:
590 case OAL_EVENT_GATTC_DISCONNECTION_COMPLETED:
591 BT_DBG("Handling Connection Stop");
592 _bt_stop_connect_time();
595 BT_DBG("The event is not currently being handled");