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.
29 #include <oal-event.h>
31 #include "bt-service-battery-monitor.h"
32 #include "bt-service-common.h"
33 #include "bt-service-event.h"
34 #include "bt-service-core-adapter.h"
36 static struct timeval scan_start;
37 static struct timeval connect_start;
38 static struct timeval app_scan_base;
39 static int scan_cnt = 0;
40 static int connect_cnt = 0;
41 static gboolean is_session_started = FALSE;
43 static GSList *scan_app_list = NULL;
48 } bt_service_oal_event_data_t;
50 _bt_battery_data_t *current_session_data = NULL;
52 static void __bt_bm_add_prev_time(uint32_t scan_time);
54 uint32_t static __bt_dm_time_diff_msec(struct timeval prev, struct timeval cur)
56 return (uint32_t)((cur.tv_sec - prev.tv_sec) * 1000.0f + (cur.tv_usec - prev.tv_usec) / 1000.0f);
59 static void __bt_display_session_data()
61 BT_DBG("Displaying session data...");
62 BT_DBG("session_start_time = %ld", current_session_data->session_start_time);
63 BT_DBG("session_end_time = %ld", current_session_data->session_end_time);
64 BT_DBG("session_scan_time = %d", current_session_data->session_scan_time);
65 BT_DBG("session_connected_time = %d", current_session_data->session_connected_time);
68 /*After reading data, the function resets it*/
69 int _bt_bm_read_data(_bt_battery_data_t *data)
71 struct timeval cur_time;
74 uint32_t idle_time = 0;
75 uint32_t energy_used = 0;
76 uint16_t scan_time_per_app = 0;
82 BT_ERR("Received NULL pointer in argument, returning...");
83 return BLUETOOTH_ERROR_NO_DATA;
86 if (_bt_get_energy_info(&tx_time, &rx_time,
87 &idle_time, &energy_used) != BLUETOOTH_ERROR_NONE) {
88 BT_ERR("Fail to get energy info");
89 return BLUETOOTH_ERROR_NOT_SUPPORT;
92 gettimeofday(&cur_time, 0);
94 data->tx_time = tx_time;
95 data->rx_time = rx_time;
96 data->idle_time = idle_time;
98 data->session_start_time = current_session_data->session_start_time;
99 data->session_end_time = time(NULL);
100 current_session_data->session_start_time = time(NULL);
101 current_session_data->session_end_time = 0;
103 data->session_scan_time = current_session_data->session_scan_time;
105 data->session_scan_time += (uint16_t)__bt_dm_time_diff_msec(scan_start, cur_time);
106 gettimeofday(&scan_start, 0);
108 current_session_data->session_scan_time = 0;
110 data->session_connected_time = current_session_data->session_connected_time;
112 data->session_connected_time += (uint16_t)__bt_dm_time_diff_msec(connect_start, cur_time);
113 gettimeofday(&connect_start, 0);
115 current_session_data->session_connected_time = 0;
117 scan_app_cnt = g_slist_length(scan_app_list);
119 if (scan_app_cnt > 0) {
120 scan_time_per_app = (uint32_t)__bt_dm_time_diff_msec(app_scan_base, cur_time) / scan_app_cnt;
121 __bt_bm_add_prev_time(scan_time_per_app);
124 gettimeofday(&app_scan_base, 0);
126 data->atm_list = current_session_data->atm_list;
127 if (data->atm_list == NULL) {
128 BT_DBG("No data transaction in this session");
129 return BLUETOOTH_ERROR_NONE;
132 BT_DBG("App-wise data transaction details");
133 for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
134 _bt_battery_app_data_t *t = (_bt_battery_app_data_t *)(l->data);
135 BT_DBG("%ld %ld %d %d %u", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes, t->time);
138 current_session_data->atm_list = NULL;
139 return BLUETOOTH_ERROR_NONE;
142 static GSList* is_app_present(GSList *start, uid_t uid, pid_t pid)
145 _bt_battery_app_data_t *t;
146 BT_INFO("Checking Memory location %p", start);
147 for (l=start; l != NULL; l = g_slist_next(l)) {
148 t = (_bt_battery_app_data_t *)(l->data);
149 if (t->uid == uid && t->pid == pid) {
150 BT_INFO("App details already exist");
157 void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int value, data_transaction_type_e type)
159 if (current_session_data == NULL) {
160 BT_ERR("Session in progress but data structure is not initialized"); //error handling
163 GSList *t = is_app_present(current_session_data->atm_list, uid, pid);
164 _bt_battery_app_data_t *app_data = NULL;
167 BT_INFO("Match not found, adding new node...");
168 app_data = g_malloc0(sizeof(_bt_battery_app_data_t));
172 app_data->rx_bytes = value;
173 else if (type == TX_DATA)
174 app_data->tx_bytes = value;
176 app_data->time = value;
177 current_session_data->atm_list = g_slist_append(current_session_data->atm_list, app_data);
180 BT_INFO("Match found, updating existing node...");
181 app_data = (_bt_battery_app_data_t *)(t->data);
183 app_data->rx_bytes += value;
184 else if (type == TX_DATA)
185 app_data->tx_bytes += value;
187 app_data->time += value;
191 void _bt_start_session_time()
193 if (is_session_started == FALSE) {
194 BT_DBG("Bt session starting...");
195 is_session_started = TRUE;
196 current_session_data = g_malloc0(sizeof(_bt_battery_data_t));
197 current_session_data->session_start_time = time(NULL);
198 current_session_data->session_end_time = 0;
199 current_session_data->session_connected_time = 0;
200 current_session_data->session_scan_time = 0;
201 current_session_data->atm_list = NULL;
203 if (current_session_data == NULL)
204 BT_ERR("Session in progress but data structure is not initialized"); //error handling
206 BT_DBG("Bt session already in progress... Returning");
210 void _bt_stop_session_time()
212 if (is_session_started == FALSE) {
213 BT_DBG("BT session not in progress... Returning"); //error handling
216 BT_DBG("Bt session ending...");
217 is_session_started = FALSE;
218 current_session_data->session_end_time = time(NULL);
219 __bt_display_session_data();
222 /* 1 app can operate the regacy and ble scan at the same time */
223 static GSList* __is_scan_app_present(GSList *start, bt_bm_scan_type_e type, uid_t uid, pid_t pid)
226 bt_bm_scan_info_t *t;
228 for (l = start; l != NULL; l = g_slist_next(l)) {
229 t = (bt_bm_scan_info_t *)(l->data);
231 /* Find the regacy scan app for Inquiry stop */
232 if (type == SCAN_REGACY && t->type != SCAN_LE) {
233 BT_INFO("app already exist");
237 if (t->uid == uid && t->pid == pid) {
238 BT_INFO("app already exist");
245 static void __bt_bm_add_prev_time(uint32_t scan_time)
248 bt_bm_scan_info_t *t;
250 for (l = scan_app_list; l != NULL; l = g_slist_next(l)) {
251 t = (bt_bm_scan_info_t *)(l->data);
252 _bt_bm_add_transaction_details(t->uid, t->pid, scan_time, TIME_DATA);
256 /* 1 regacy scan is only allowed in the platform
257 * BLE scan is allowed for many apps
259 /* When a app is added, we should add and reset the time. */
260 void _bt_bm_add_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
262 bt_bm_scan_info_t *scan_info = NULL;
263 GSList *app_list = NULL;
265 uint32_t scan_time_per_app = 0;
267 BT_DBG("Scan type: %d", type);
270 app_cnt = g_slist_length(scan_app_list);
271 app_list = __is_scan_app_present(scan_app_list, SCAN_BOTH, uid, pid);
275 /* app try to scan both Regacy and LE */
276 scan_info = (bt_bm_scan_info_t *)(app_list->data);
278 if (scan_info == NULL) {
279 BT_ERR("Can't get the scan info");
283 BT_DBG("Previous type: %d", scan_info->type);
285 if (scan_info->type == type) {
286 BT_ERR("Same scan type is doing");
290 scan_info->type = SCAN_BOTH;
292 scan_info = g_malloc0(sizeof(bt_bm_scan_info_t));
293 scan_info->uid = uid;
294 scan_info->pid = pid;
295 scan_info->type = type;
298 struct timeval cur_time;
300 gettimeofday(&cur_time, 0);
302 scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
303 __bt_bm_add_prev_time(scan_time_per_app);
305 /* Update the base time */
306 gettimeofday(&app_scan_base, 0);
309 scan_app_list = g_slist_append(scan_app_list, scan_info);
313 /* When a app is removed, we should add and reset the time. */
314 void _bt_bm_remove_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
316 bt_bm_scan_info_t *scan_info = NULL;
317 GSList *app_list = NULL;
319 uint32_t scan_time_per_app = 0;
321 BT_DBG("Scan type: %d", type);
323 if (scan_app_list == NULL) {
324 BT_ERR("No scan app in list");
328 app_cnt = g_slist_length(scan_app_list);
331 BT_ERR("No scan app in list");
335 app_list = __is_scan_app_present(scan_app_list, type, uid, pid);
338 struct timeval cur_time;
340 scan_info = (bt_bm_scan_info_t *)(app_list->data);
342 if (scan_info->type == SCAN_BOTH) {
343 scan_info->type = (scan_info->type == SCAN_REGACY) ? SCAN_LE : SCAN_REGACY;
347 gettimeofday(&cur_time, 0);
349 scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
350 __bt_bm_add_prev_time(scan_time_per_app);
352 /* Update the base time */
353 gettimeofday(&app_scan_base, 0);
355 scan_app_list = g_slist_remove(scan_app_list, scan_info);
361 void _bt_start_scan_time()
363 if (current_session_data != NULL) {
365 BT_DBG("Starting scan time");
366 gettimeofday(&scan_start, 0);
367 gettimeofday(&app_scan_base, 0);
371 BT_ERR("Data structure uninitialized"); //error handling
375 void _bt_stop_scan_time()
377 if (scan_cnt == 0 || current_session_data == NULL)
378 BT_ERR("Error encountered, returning..."); //error handling
382 struct timeval cur_time;
384 gettimeofday(&cur_time, 0);
385 current_session_data->session_scan_time += (uint16_t)(__bt_dm_time_diff_msec(scan_start, cur_time));
386 gettimeofday(&scan_start, 0);
387 gettimeofday(&app_scan_base, 0);
392 void _bt_start_connect_time()
394 if (current_session_data != NULL) {
395 if (connect_cnt == 0) {
396 BT_DBG("Starting connect time");
397 gettimeofday(&connect_start, 0);
402 BT_ERR("Data structure uninitialized"); //error handling
406 void _bt_stop_connect_time()
408 if(connect_cnt == 0 || current_session_data == NULL) {
409 BT_ERR("Error encountered, returning..."); //error handling
413 if(connect_cnt == 0) {
414 struct timeval cur_time;
416 gettimeofday(&cur_time, 0);
417 current_session_data->session_connected_time += (uint16_t)(__bt_dm_time_diff_msec(connect_start, cur_time));
422 static void _bt_notify_battery_data(void)
425 _bt_battery_data_t *data = NULL;
428 data = g_new0(_bt_battery_data_t, 1);
429 result = _bt_bm_read_data(data);
430 GVariant *out_var = NULL, *param = NULL;
433 if (result != BLUETOOTH_ERROR_NONE) {
434 BT_ERR("Battery data not collected");
437 bt_battery_dbus_data_t dbus_data;
438 memset(&dbus_data, 0, sizeof(bt_battery_dbus_data_t));
439 dbus_data.session_start_time = data->session_start_time;
440 dbus_data.session_end_time = data->session_end_time;
441 dbus_data.session_scan_time = data->session_scan_time;
442 dbus_data.session_connected_time = data->session_connected_time;
443 dbus_data.tx_time = data->tx_time;
444 dbus_data.rx_time = data->rx_time;
445 dbus_data.idle_time = data->idle_time;
447 /*Populating app data*/
449 for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
450 bt_battery_app_data *t = (bt_battery_app_data *)(l->data);
451 memcpy(&dbus_data.app_data[n], t, sizeof(bt_battery_app_data));
454 dbus_data.num_app = n;
456 info = g_array_new(FALSE, FALSE, sizeof(gchar));
457 g_array_append_vals(info, &dbus_data, sizeof(bt_battery_dbus_data_t));
459 out_var = g_variant_new_from_data((const GVariantType *)"ay",
460 info->data, info->len,
463 param = g_variant_new("(iv)", result, out_var);
464 _bt_send_event(BT_ADAPTER_EVENT,
465 BLUETOOTH_EVENT_DISABLED_BATTERY_DATA,
468 g_slist_free(data->atm_list);
470 g_array_free(info, TRUE);
474 void _bt_bm_event_handler(gpointer data)
476 bt_service_oal_event_data_t *oal_event = data;
477 int event_type = oal_event->type;
480 case OAL_EVENT_ADAPTER_ENABLED:
481 BT_DBG("Handling Adapter Enabled");
482 _bt_start_session_time();
484 case OAL_EVENT_ADAPTER_DISABLED:
485 BT_DBG("Handling Adapter Disabled");
486 _bt_stop_session_time();
487 _bt_notify_battery_data();
489 case OAL_EVENT_ADAPTER_INQUIRY_STARTED:
490 case OAL_EVENT_BLE_DISCOVERY_STARTED:
491 BT_DBG("Handling Adapter Discovery Start");
492 _bt_start_scan_time();
494 case OAL_EVENT_ADAPTER_INQUIRY_FINISHED:
495 /* Remove the regacy scan app */
496 _bt_bm_remove_scan_app(SCAN_REGACY, 0, 0);
498 _bt_stop_scan_time();
500 case OAL_EVENT_BLE_DISCOVERY_STOPPED:
501 BT_DBG("Handling Adapter Discovery Stop");
502 _bt_stop_scan_time();
504 case OAL_EVENT_SOCKET_OUTGOING_CONNECTED:
505 case OAL_EVENT_GATTC_CONNECTION_COMPLETED:
506 BT_DBG("Handling Connection Start");
507 _bt_start_connect_time();
509 case OAL_EVENT_SOCKET_DISCONNECTED:
510 case OAL_EVENT_GATTC_DISCONNECTION_COMPLETED:
511 BT_DBG("Handling Connection Stop");
512 _bt_stop_connect_time();
515 BT_DBG("The event is not currently being handled");