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"
43 #define BT_BM_SESSION_TIMEOUT 600
45 static struct timeval scan_start;
46 static struct timeval connect_start;
47 static struct timeval app_scan_base;
48 static int scan_cnt = 0;
49 static int connect_cnt = 0;
50 static gboolean is_session_started = FALSE;
51 static guint session_timer = 0;
53 static GSList *scan_app_list = NULL;
58 } bt_service_oal_event_data_t;
60 _bt_battery_data_t *current_session_data = NULL;
62 static void __bt_bm_add_prev_time(uint32_t scan_time);
63 static int __bt_start_session_time(void);
64 static void __bt_stop_session_time(void);
65 static bool __bt_bm_session_timeout_cb(void);
67 uint32_t static __bt_dm_time_diff_msec(struct timeval prev, struct timeval cur)
69 return (uint32_t)((cur.tv_sec - prev.tv_sec) * 1000.0f + (cur.tv_usec - prev.tv_usec) / 1000.0f);
72 static void __bt_display_session_data()
74 BT_DBG("Displaying session data...");
76 if (current_session_data == NULL) {
77 BT_ERR("Session in progress but data structure is not initialized");
81 BT_DBG("session_start_time = %ld", current_session_data->session_start_time);
82 BT_DBG("session_end_time = %ld", current_session_data->session_end_time);
83 BT_DBG("session_scan_time = %d", current_session_data->session_scan_time);
84 BT_DBG("session_connected_time = %d", current_session_data->session_connected_time);
87 /*After reading data, the function resets it*/
88 int _bt_bm_read_data(_bt_battery_data_t *data)
90 struct timeval cur_time;
93 uint32_t idle_time = 0;
94 uint32_t energy_used = 0;
95 uint16_t scan_time_per_app = 0;
101 BT_ERR("Received NULL pointer in argument, returning...");
102 return BLUETOOTH_ERROR_NO_DATA;
105 if (_bt_get_energy_info(&tx_time, &rx_time,
106 &idle_time, &energy_used) != BLUETOOTH_ERROR_NONE) {
107 BT_ERR("Fail to get energy info");
108 return BLUETOOTH_ERROR_NOT_SUPPORT;
111 if (is_session_started == FALSE) {
112 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
113 BT_ERR("Fail to start session time");
114 return BLUETOOTH_ERROR_NOT_SUPPORT;
118 if (current_session_data == NULL) {
119 BT_ERR("Session in progress but data structure is not initialized");
120 return BLUETOOTH_ERROR_INTERNAL;
123 gettimeofday(&cur_time, 0);
125 data->tx_time = tx_time;
126 data->rx_time = rx_time;
127 data->idle_time = idle_time;
129 data->session_start_time = current_session_data->session_start_time;
130 data->session_end_time = time(NULL);
131 current_session_data->session_start_time = time(NULL);
132 current_session_data->session_end_time = 0;
134 data->session_scan_time = current_session_data->session_scan_time;
136 data->session_scan_time += (uint16_t)__bt_dm_time_diff_msec(scan_start, cur_time);
137 gettimeofday(&scan_start, 0);
139 current_session_data->session_scan_time = 0;
141 data->session_connected_time = current_session_data->session_connected_time;
143 data->session_connected_time += (uint16_t)__bt_dm_time_diff_msec(connect_start, cur_time);
144 gettimeofday(&connect_start, 0);
146 current_session_data->session_connected_time = 0;
148 scan_app_cnt = g_slist_length(scan_app_list);
150 if (scan_app_cnt > 0) {
151 scan_time_per_app = (uint32_t)__bt_dm_time_diff_msec(app_scan_base, cur_time) / scan_app_cnt;
152 __bt_bm_add_prev_time(scan_time_per_app);
155 gettimeofday(&app_scan_base, 0);
157 /* Note that this is a "shallow" copy. The pointers are copied but the actual data isn't. */
158 data->atm_list = g_slist_copy(current_session_data->atm_list);
159 current_session_data->atm_list = NULL;
161 BT_DBG("App-wise data transaction details");
162 for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
163 _bt_battery_app_data_t *t = (_bt_battery_app_data_t *)(l->data);
164 BT_DBG("%ld %ld %d %d %u", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes, t->time);
167 /* Reset the session timer */
169 g_source_remove(session_timer);
171 session_timer = g_timeout_add_seconds(BT_BM_SESSION_TIMEOUT,
172 (GSourceFunc)__bt_bm_session_timeout_cb, NULL);
174 return BLUETOOTH_ERROR_NONE;
177 static GSList* is_app_present(GSList *start, uid_t uid, pid_t pid)
180 _bt_battery_app_data_t *t;
181 BT_INFO("Checking Memory location %p", start);
182 for (l=start; l != NULL; l = g_slist_next(l)) {
183 t = (_bt_battery_app_data_t *)(l->data);
184 if (t->uid == uid && t->pid == pid) {
185 BT_INFO("App details already exist");
192 void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int value, data_transaction_type_e type)
194 if (is_session_started == FALSE)
195 __bt_start_session_time();
197 if (current_session_data == NULL) {
198 BT_ERR("Session in progress but data structure is not initialized");
201 GSList *t = is_app_present(current_session_data->atm_list, uid, pid);
202 _bt_battery_app_data_t *app_data = NULL;
205 BT_INFO("Match not found, adding new node...");
206 app_data = g_malloc0(sizeof(_bt_battery_app_data_t));
210 app_data->rx_bytes = value;
211 else if (type == TX_DATA)
212 app_data->tx_bytes = value;
214 app_data->time = value;
215 current_session_data->atm_list = g_slist_append(current_session_data->atm_list, app_data);
218 BT_INFO("Match found, updating existing node...");
219 app_data = (_bt_battery_app_data_t *)(t->data);
221 app_data->rx_bytes += value;
222 else if (type == TX_DATA)
223 app_data->tx_bytes += value;
225 app_data->time += value;
229 static bool __bt_bm_session_timeout_cb(void)
231 BT_INFO("No data read calls during the time.");
233 __bt_stop_session_time();
239 static int __bt_start_session_time(void)
243 if (is_session_started == TRUE) {
244 BT_ERR("Session is already started");
245 return BLUETOOTH_ERROR_ALREADY_INITIALIZED;
248 if (vconf_get_bool(VCONFKEY_BATTERY_MONITOR_STATUS, &state) != 0) {
249 BT_ERR("vconf_get_bool failed");
250 return BLUETOOTH_ERROR_INTERNAL;
254 BT_ERR("Battery is not monitoring in now");
255 return BLUETOOTH_ERROR_NOT_SUPPORT;
258 BT_DBG("Bt session starting...");
259 is_session_started = TRUE;
261 if (current_session_data == NULL)
262 current_session_data = g_malloc0(sizeof(_bt_battery_data_t));
264 current_session_data->session_start_time = time(NULL);
265 current_session_data->session_end_time = 0;
266 current_session_data->session_connected_time = 0;
267 current_session_data->session_scan_time = 0;
268 current_session_data->atm_list = NULL;
270 /* After starting session if there is no read data call during the specific time,
271 * stop the session time to avoid the exceed of session data.
274 g_source_remove(session_timer);
276 session_timer = g_timeout_add_seconds(BT_BM_SESSION_TIMEOUT,
277 (GSourceFunc)__bt_bm_session_timeout_cb, NULL);
279 return BLUETOOTH_ERROR_NONE;
282 static void __bt_stop_session_time(void)
285 g_source_remove(session_timer);
289 if (is_session_started == FALSE) {
290 BT_DBG("BT session not in progress... Returning");
294 __bt_display_session_data();
296 BT_DBG("Bt session ending...");
297 is_session_started = FALSE;
299 if (current_session_data != NULL) {
300 g_slist_free_full(current_session_data->atm_list, g_free);
301 g_free(current_session_data);
302 current_session_data = NULL;
306 /* 1 app can operate the regacy and ble scan at the same time */
307 static GSList* __is_scan_app_present(GSList *start, bt_bm_scan_type_e type, uid_t uid, pid_t pid)
310 bt_bm_scan_info_t *t;
312 for (l = start; l != NULL; l = g_slist_next(l)) {
313 t = (bt_bm_scan_info_t *)(l->data);
315 /* Find the regacy scan app for Inquiry stop */
316 if (type == SCAN_REGACY && t->type != SCAN_LE) {
317 BT_INFO("app already exist");
321 if (t->uid == uid && t->pid == pid) {
322 BT_INFO("app already exist");
329 static void __bt_bm_add_prev_time(uint32_t scan_time)
332 bt_bm_scan_info_t *t;
334 for (l = scan_app_list; l != NULL; l = g_slist_next(l)) {
335 t = (bt_bm_scan_info_t *)(l->data);
336 _bt_bm_add_transaction_details(t->uid, t->pid, scan_time, TIME_DATA);
340 /* 1 regacy scan is only allowed in the platform
341 * BLE scan is allowed for many apps
343 /* When a app is added, we should add and reset the time. */
344 void _bt_bm_add_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
346 bt_bm_scan_info_t *scan_info = NULL;
347 GSList *app_list = NULL;
349 uint32_t scan_time_per_app = 0;
351 BT_DBG("Scan type: %d", type);
354 app_cnt = g_slist_length(scan_app_list);
355 app_list = __is_scan_app_present(scan_app_list, SCAN_BOTH, uid, pid);
359 /* app try to scan both Regacy and LE */
360 scan_info = (bt_bm_scan_info_t *)(app_list->data);
362 if (scan_info == NULL) {
363 BT_ERR("Can't get the scan info");
367 BT_DBG("Previous type: %d", scan_info->type);
369 if (scan_info->type == type) {
370 BT_ERR("Same scan type is doing");
374 scan_info->type = SCAN_BOTH;
376 scan_info = g_malloc0(sizeof(bt_bm_scan_info_t));
377 scan_info->uid = uid;
378 scan_info->pid = pid;
379 scan_info->type = type;
382 struct timeval cur_time;
384 gettimeofday(&cur_time, 0);
386 scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
387 __bt_bm_add_prev_time(scan_time_per_app);
389 /* Update the base time */
390 gettimeofday(&app_scan_base, 0);
393 scan_app_list = g_slist_append(scan_app_list, scan_info);
397 /* When a app is removed, we should add and reset the time. */
398 void _bt_bm_remove_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
400 bt_bm_scan_info_t *scan_info = NULL;
401 GSList *app_list = NULL;
403 uint32_t scan_time_per_app = 0;
405 BT_DBG("Scan type: %d", type);
407 if (scan_app_list == NULL) {
408 BT_ERR("No scan app in list");
412 app_cnt = g_slist_length(scan_app_list);
415 BT_ERR("No scan app in list");
419 app_list = __is_scan_app_present(scan_app_list, type, uid, pid);
422 struct timeval cur_time;
424 scan_info = (bt_bm_scan_info_t *)(app_list->data);
426 if (scan_info->type == SCAN_BOTH) {
427 scan_info->type = (scan_info->type == SCAN_REGACY) ? SCAN_LE : SCAN_REGACY;
431 gettimeofday(&cur_time, 0);
433 scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
434 __bt_bm_add_prev_time(scan_time_per_app);
436 /* Update the base time */
437 gettimeofday(&app_scan_base, 0);
439 scan_app_list = g_slist_remove(scan_app_list, scan_info);
445 void _bt_start_scan_time()
447 if (is_session_started == FALSE) {
448 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
449 BT_ERR("Fail to start session time");
454 if (current_session_data != NULL) {
456 BT_DBG("Starting scan time");
457 gettimeofday(&scan_start, 0);
458 gettimeofday(&app_scan_base, 0);
462 BT_ERR("Data structure uninitialized");
466 void _bt_stop_scan_time()
468 if (is_session_started == FALSE) {
469 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
470 BT_ERR("Fail to start session time");
475 if (scan_cnt == 0 || current_session_data == NULL)
476 BT_ERR("Error encountered, returning...");
480 struct timeval cur_time;
482 gettimeofday(&cur_time, 0);
483 current_session_data->session_scan_time += (uint16_t)(__bt_dm_time_diff_msec(scan_start, cur_time));
484 gettimeofday(&scan_start, 0);
485 gettimeofday(&app_scan_base, 0);
490 void _bt_start_connect_time()
492 if (is_session_started == FALSE) {
493 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
494 BT_ERR("Fail to start session time");
499 if (current_session_data != NULL) {
500 if (connect_cnt == 0) {
501 BT_DBG("Starting connect time");
502 gettimeofday(&connect_start, 0);
507 BT_ERR("Data structure uninitialized");
511 void _bt_stop_connect_time()
513 if (is_session_started == FALSE) {
514 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
515 BT_ERR("Fail to start session time");
520 if(connect_cnt == 0 || current_session_data == NULL) {
521 BT_ERR("Error encountered, returning...");
524 if(connect_cnt == 0) {
525 struct timeval cur_time;
527 gettimeofday(&cur_time, 0);
528 current_session_data->session_connected_time += (uint16_t)(__bt_dm_time_diff_msec(connect_start, cur_time));
533 static void __bt_notify_battery_data(void)
536 _bt_battery_data_t *data = NULL;
539 data = g_new0(_bt_battery_data_t, 1);
540 result = _bt_bm_read_data(data);
541 GVariant *out_var = NULL, *param = NULL;
544 if (result != BLUETOOTH_ERROR_NONE) {
545 BT_ERR("Battery data not collected");
550 bt_battery_dbus_data_t dbus_data;
551 memset(&dbus_data, 0, sizeof(bt_battery_dbus_data_t));
552 dbus_data.session_start_time = data->session_start_time;
553 dbus_data.session_end_time = data->session_end_time;
554 dbus_data.session_scan_time = data->session_scan_time;
555 dbus_data.session_connected_time = data->session_connected_time;
556 dbus_data.tx_time = data->tx_time;
557 dbus_data.rx_time = data->rx_time;
558 dbus_data.idle_time = data->idle_time;
560 /*Populating app data*/
562 for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
563 bt_battery_app_data *t = (bt_battery_app_data *)(l->data);
564 memcpy(&dbus_data.app_data[n], t, sizeof(bt_battery_app_data));
567 dbus_data.num_app = n;
569 info = g_array_new(FALSE, FALSE, sizeof(gchar));
570 g_array_append_vals(info, &dbus_data, sizeof(bt_battery_dbus_data_t));
572 out_var = g_variant_new_from_data((const GVariantType *)"ay",
573 info->data, info->len,
576 param = g_variant_new("(iv)", result, out_var);
577 _bt_send_event(BT_ADAPTER_EVENT,
578 BLUETOOTH_EVENT_DISABLED_BATTERY_DATA,
581 g_slist_free_full(data->atm_list, g_free);
583 g_array_free(info, TRUE);
587 void _bt_bm_event_handler(gpointer data)
589 bt_service_oal_event_data_t *oal_event = data;
590 int event_type = oal_event->type;
593 case OAL_EVENT_ADAPTER_ENABLED:
594 BT_DBG("Handling Adapter Enabled");
595 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE)
596 BT_ERR("Fail to start session time");
598 case OAL_EVENT_ADAPTER_DISABLED:
599 BT_DBG("Handling Adapter Disabled");
600 if (is_session_started == TRUE) {
601 __bt_notify_battery_data();
602 __bt_stop_session_time();
605 case OAL_EVENT_ADAPTER_INQUIRY_STARTED:
606 case OAL_EVENT_BLE_DISCOVERY_STARTED:
607 BT_DBG("Handling Adapter Discovery Start");
608 _bt_start_scan_time();
610 case OAL_EVENT_ADAPTER_INQUIRY_FINISHED:
611 /* Remove the regacy scan app */
612 _bt_bm_remove_scan_app(SCAN_REGACY, 0, 0);
614 _bt_stop_scan_time();
616 case OAL_EVENT_BLE_DISCOVERY_STOPPED:
617 BT_DBG("Handling Adapter Discovery Stop");
618 _bt_stop_scan_time();
620 case OAL_EVENT_SOCKET_OUTGOING_CONNECTED:
621 case OAL_EVENT_GATTC_CONNECTION_COMPLETED:
622 BT_DBG("Handling Connection Start");
623 _bt_start_connect_time();
625 case OAL_EVENT_SOCKET_DISCONNECTED:
626 case OAL_EVENT_GATTC_DISCONNECTION_COMPLETED:
627 BT_DBG("Handling Connection Stop");
628 _bt_stop_connect_time();
631 BT_DBG("The event is not currently being handled");