Handling le connection interval 98/183498/1
authorinjun.yang <injun.yang@samsung.com>
Fri, 6 Jul 2018 04:56:23 +0000 (13:56 +0900)
committerinjun.yang <injun.yang@samsung.com>
Fri, 6 Jul 2018 04:56:23 +0000 (13:56 +0900)
[Problem] Whenever several application set the le connection interval,
 it overwirted and affect LE throughput
[Cause & Measure] Manage all demand and keep the minimum interval
 [Checking Method] Set le connection interval

Change-Id: I32b75169c30e7fae8e7419785e5aaa15c6ad8f62
Signed-off-by: injun.yang <injun.yang@samsung.com>
bt-service/bt-request-handler.c
bt-service/bt-service-device.c
bt-service/bt-service-event-receiver.c
bt-service/include/bt-service-device.h

index e1a036290af1f783dae74c965506693e0a03a89e..5df003cfea3c215ad460b030e4c22bd93ce57266 100644 (file)
@@ -292,7 +292,6 @@ fail:
                g_variant_unref(param3);
                g_variant_unref(param4);
                g_variant_unref(param5);
-//             g_free(sender);
        }
 
        FN_END;
@@ -707,15 +706,19 @@ int __bt_bluez_request(int function_name,
                break;
        }
        case BT_LE_CONN_UPDATE: {
+               char *sender = NULL;
                bluetooth_device_address_t local_address = { {0} };
                bluetooth_le_connection_param_t parameters = {0};
 
+               sender = (char *)g_dbus_method_invocation_get_sender(context);
+
                __bt_service_get_parameters(in_param1, &local_address,
                                sizeof(bluetooth_device_address_t));
                __bt_service_get_parameters(in_param2, &parameters,
                                sizeof(bluetooth_le_connection_param_t));
 
-               result =  _bt_le_conn_update(local_address.addr,
+               result =  _bt_le_conn_update(sender,
+                                       local_address.addr,
                                        parameters.interval_min,
                                        parameters.interval_max,
                                        parameters.latency,
@@ -960,6 +963,7 @@ int __bt_bluez_request(int function_name,
                break;
        }
        case BT_UPDATE_LE_CONNECTION_MODE: {
+               char *sender = NULL;
                bluetooth_device_address_t remote_address = { { 0 } };
                bluetooth_le_connection_param_t param = { 0 };
                bluetooth_le_connection_mode_t mode = BLUETOOTH_LE_CONNECTION_MODE_BALANCED;
@@ -973,7 +977,10 @@ int __bt_bluez_request(int function_name,
                if (result != BLUETOOTH_ERROR_NONE)
                        break;
 
-               result = _bt_le_conn_update(remote_address.addr,
+               sender = (char *)g_dbus_method_invocation_get_sender(context);
+
+               result = _bt_le_conn_update(sender,
+                               remote_address.addr,
                                param.interval_min,
                                param.interval_max,
                                param.latency,
index 3a50a4ef650708717eb1b1ea1433d9ccaadb9bfe..49bc041fc9b4a31b3ec709881858b9bdca217bce 100644 (file)
@@ -90,11 +90,28 @@ typedef struct {
        gboolean auto_connect;
 } bt_pending_le_conn_info_s;
 
+typedef struct {
+       char *address;
+       float interval_min;
+       float interval_max;
+       GSList *senders;
+} bt_connected_le_dev_t;
+
+typedef struct {
+       char *sender;
+       float interval_min;
+       float interval_max;
+       guint16 latency;
+       guint16 time_out;
+       float key;
+} bt_le_conn_param_t;
+
 gboolean is_device_creating;
 bt_funcion_data_t *bonding_info;
 bt_funcion_data_t *searching_info;
 bt_funcion_data_t *att_mtu_req_info;
 
+static GSList *le_connected_dev_list = NULL;
 static GSList *pin_info_list = NULL;
 static bt_pending_le_conn_info_s *pending_le_conn_info = NULL;
 static guint pending_le_conn_timer_id = 0;
@@ -2315,59 +2332,24 @@ int _bt_get_rssi_strength(bluetooth_device_address_t *bd_addr,
        return ret;
 }
 
-int _bt_le_conn_update(unsigned char *device_address,
+static int __bt_le_set_conn_parameter(const char *address,
                                float interval_min, float interval_max,
                                guint16 latency, guint16 time_out)
 {
-       char address[BT_ADDRESS_STRING_SIZE] = { 0 };
        gchar *device_path = NULL;
        GError *error = NULL;
        GDBusProxy *device_proxy = NULL;
        GDBusConnection *conn;
        GVariant *reply;
        guint32 min, max, to;
-       guint32 min_supervision_to;
        int ret = BLUETOOTH_ERROR_NONE;
 
-       BT_CHECK_PARAMETER(device_address, return);
+       BT_CHECK_PARAMETER(address, return);
 
        BT_INFO("Min interval: %f, Max interval: %f, Latency: %u, Supervision timeout: %u",
                        interval_min, interval_max, latency, time_out);
 
-       if (interval_min > interval_max ||
-                       interval_min < BT_LE_CONN_INTERVAL_MIN ||
-                       interval_max > BT_LE_CONN_INTERVAL_MAX) {
-               ret = BLUETOOTH_ERROR_INVALID_PARAM;
-               goto fail;
-       }
-
-       if (time_out < BT_LE_CONN_SUPER_TO_MIN ||
-                       time_out > BT_LE_CONN_SUPER_TO_MAX) {
-               ret = BLUETOOTH_ERROR_INVALID_PARAM;
-               goto fail;
-       }
-
-       if (latency > BT_LE_CONN_SLAVE_LATENCY_MAX) {
-               ret = BLUETOOTH_ERROR_INVALID_PARAM;
-               goto fail;
-       }
-
-       /*
-        * The Supervision_Timeout in milliseconds shall be larger than
-        * (1 + Conn_Latency) * Conn_Interval_Max * 2,
-        * where Conn_Interval_Max is given in milliseconds.
-        */
-       min_supervision_to = (1 + latency) * interval_max * 2;
-       if (time_out <= min_supervision_to) {
-               ret = BLUETOOTH_ERROR_INVALID_PARAM;
-               goto fail;
-       }
-
-       _bt_convert_addr_type_to_string(address, device_address);
-
-       BT_DBG("Remote device address: %s", address);
-
-       device_path = _bt_get_device_object_path(address);
+       device_path = _bt_get_device_object_path((char *)address);
 
        if (device_path == NULL) {
                BT_ERR("device_path NULL");
@@ -2418,6 +2400,306 @@ fail:
        return ret;
 }
 
+static void __bt_le_conn_param_free(void *data)
+{
+       bt_le_conn_param_t *param = (bt_le_conn_param_t *)data;
+
+       BT_DBG("%s", param->sender);
+       g_free(param->sender);
+       g_free(param);
+}
+
+static gint __bt_compare_le_conn_param_key(gpointer *a, gpointer *b)
+{
+       bt_le_conn_param_t *parama = (bt_le_conn_param_t *)a;
+       bt_le_conn_param_t *paramb = (bt_le_conn_param_t *)b;
+
+       return parama->key > paramb->key;
+}
+
+static bt_connected_le_dev_t *__bt_get_le_connected_dev_info(const char *address)
+{
+       GSList *l = NULL;
+       bt_connected_le_dev_t *dev;
+
+       if (!address)
+               return NULL;
+
+       for (l = le_connected_dev_list; l; l = g_slist_next(l)) {
+               dev = l->data;
+
+               if (g_strcmp0(dev->address, address) == 0)
+                       return dev;
+       }
+       return NULL;
+}
+
+static bt_le_conn_param_t *__bt_get_le_conn_param_info(bt_connected_le_dev_t *dev, const char *sender)
+{
+       GSList *l = NULL;
+       bt_le_conn_param_t *param = NULL;
+
+       if (!dev || !sender)
+               return NULL;
+
+       for (l = dev->senders; l; l = g_slist_next(l)) {
+               param = l->data;
+               if (g_strcmp0(param->sender, sender) == 0)
+                       return param;
+       }
+
+       return NULL;
+}
+
+int _bt_add_le_conn_param_info(const char *address, const char *sender,
+                       float interval_min, float interval_max, guint16 latency, guint16 time_out)
+{
+       bt_connected_le_dev_t *dev = NULL;
+       bt_le_conn_param_t *param = NULL;
+       bt_le_conn_param_t *data = NULL;
+
+       if (!address || !sender)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       dev = __bt_get_le_connected_dev_info(address);
+       if (!dev)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       param = __bt_get_le_conn_param_info(dev, sender);
+
+       data = g_malloc0(sizeof(bt_le_conn_param_t));
+       data->sender = g_strdup(sender);
+       data->interval_min = interval_min;
+       data->interval_max = interval_max;
+       data->latency = latency;
+       data->time_out = time_out;
+       data->key = interval_min + (interval_max - interval_min)/2;
+
+       if (param == NULL) {
+               BT_DBG("Add param %s %s %f %f", address, sender, interval_min, interval_max);
+               dev->senders = g_slist_append(dev->senders, data);
+       } else {
+               BT_DBG("Update param %s %s %f %f", address, sender, interval_min, interval_max);
+               dev->senders = g_slist_remove(dev->senders, param);
+               g_free(param->sender);
+               g_free(param);
+               dev->senders = g_slist_append(dev->senders, data);
+       }
+
+       /* Sorting. First element have the minimum interval */
+       dev->senders = g_slist_sort(dev->senders,
+                                       (GCompareFunc)__bt_compare_le_conn_param_key);
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_remove_le_conn_param_info(const char *address, const char *sender, gboolean *is_removed)
+{
+       bt_connected_le_dev_t *dev = NULL;
+       bt_le_conn_param_t *param = NULL;
+
+       if (!address || !sender)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       dev = __bt_get_le_connected_dev_info(address);
+       if (!dev)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       param = __bt_get_le_conn_param_info(dev, sender);
+       if (param) {
+               BT_DBG("Remove param %s %s ", address, sender);
+               dev->senders = g_slist_remove(dev->senders, param);
+               g_free(param->sender);
+               g_free(param);
+               *is_removed = TRUE;
+       } else
+               *is_removed = FALSE;
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_remove_all_le_conn_param_info(const char *sender)
+{
+       GSList *l = NULL;
+       bt_connected_le_dev_t *dev = NULL;
+       bt_le_conn_param_t *param = NULL;
+       gboolean is_removed = FALSE;
+       char *sender_new = NULL;
+       unsigned char addr[BLUETOOTH_ADDRESS_LENGTH];
+       int ret = BLUETOOTH_ERROR_NONE;
+
+       if (!sender)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       for (l = le_connected_dev_list; l; l = g_slist_next(l)) {
+               dev = l->data;
+               _bt_remove_le_conn_param_info(dev->address, sender, &is_removed);
+
+               if (is_removed) {
+                       BT_INFO("Sender terminated. Update le conn interval [senders %d]",
+                                               g_slist_length(dev->senders));
+                       if (g_slist_length(dev->senders) > 0) {
+                               param = dev->senders->data;
+                               BT_DBG("dev %f %f, param %f %f", dev->interval_min, dev->interval_max,
+                                               param->interval_min, param->interval_max);
+
+                               if (dev->interval_min != param->interval_min ||
+                                       dev->interval_max != param->interval_max) {
+                                       sender_new = g_strdup(param->sender);
+
+                                       _bt_convert_addr_string_to_type(addr, dev->address);
+                                       ret = _bt_le_conn_update(sender_new, addr,
+                                                               param->interval_min,  param->interval_max,
+                                                               param->latency, param->time_out);
+                                       g_free(sender_new);
+
+                                       if (ret != BLUETOOTH_ERROR_NONE)
+                                               BT_ERR("Unable to set le connection parameter");
+                               }
+                       } else {
+                               BT_INFO("Set the default interval");
+
+                               bluetooth_le_connection_param_t param = { 0 };
+                                _bt_get_le_connection_parameter(
+                                                       BLUETOOTH_LE_CONNECTION_MODE_LOW_POWER,
+                                                       &param);
+
+                               ret = __bt_le_set_conn_parameter(dev->address,
+                                                               param.interval_min, param.interval_max,
+                                                               param.latency, param.timeout);
+                               if (ret == BLUETOOTH_ERROR_NONE) {
+                                       dev->interval_min = param.interval_min;
+                                       dev->interval_max = param.interval_max;
+                               }
+                       }
+               }
+       }
+
+       return ret;
+}
+
+void _bt_add_le_connected_dev_info(const char *address)
+{
+       bt_connected_le_dev_t *dev = NULL;
+
+       if (!address)
+               return;
+
+       dev = g_malloc0(sizeof(bt_connected_le_dev_t));
+       dev->address = g_strdup(address);
+
+       le_connected_dev_list = g_slist_append(le_connected_dev_list, dev);
+
+       return;
+}
+
+void _bt_remove_le_connected_dev_info(const char *address)
+{
+       bt_connected_le_dev_t *dev = NULL;
+
+       if (!address)
+               return;
+
+       dev = __bt_get_le_connected_dev_info(address);
+       if (!dev)
+               return;
+
+       g_slist_free_full(dev->senders, __bt_le_conn_param_free);
+       le_connected_dev_list = g_slist_remove(le_connected_dev_list, dev);
+       g_free(dev->address);
+       g_free(dev);
+
+       return;
+}
+
+int _bt_le_conn_update(const char *sender,
+                               unsigned char *device_address,
+                               float interval_min, float interval_max,
+                               guint16 latency, guint16 time_out)
+{
+       char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+       guint32 min_supervision_to;
+       bt_connected_le_dev_t *dev = NULL;
+       bt_le_conn_param_t *param = NULL;
+       gboolean is_removed = FALSE;
+       int ret = BLUETOOTH_ERROR_NONE;
+
+       BT_CHECK_PARAMETER(device_address, return);
+
+       BT_INFO("Sender %s, Min interval: %f, Max interval: %f, Latency: %u, Supervision timeout: %u",
+                       sender, interval_min, interval_max, latency, time_out);
+
+       if (interval_min > interval_max ||
+                       interval_min < BT_LE_CONN_INTERVAL_MIN ||
+                       interval_max > BT_LE_CONN_INTERVAL_MAX) {
+               ret = BLUETOOTH_ERROR_INVALID_PARAM;
+               goto fail;
+       }
+
+       if (time_out < BT_LE_CONN_SUPER_TO_MIN ||
+                       time_out > BT_LE_CONN_SUPER_TO_MAX) {
+               ret = BLUETOOTH_ERROR_INVALID_PARAM;
+               goto fail;
+       }
+
+       if (latency > BT_LE_CONN_SLAVE_LATENCY_MAX) {
+               ret = BLUETOOTH_ERROR_INVALID_PARAM;
+               goto fail;
+       }
+
+       /*
+        * The Supervision_Timeout in milliseconds shall be larger than
+        * (1 + Conn_Latency) * Conn_Interval_Max * 2,
+        * where Conn_Interval_Max is given in milliseconds.
+        */
+       min_supervision_to = (1 + latency) * interval_max * 2;
+       if (time_out <= min_supervision_to) {
+               ret = BLUETOOTH_ERROR_INVALID_PARAM;
+               goto fail;
+       }
+
+       _bt_convert_addr_type_to_string(address, device_address);
+       BT_DBG("Remote device address: %s", address);
+
+       _bt_add_le_conn_param_info(address, sender, interval_min, interval_max, 0, 2000);
+
+       dev = __bt_get_le_connected_dev_info(address);
+       if (dev == NULL) {
+               ret = BLUETOOTH_ERROR_NOT_CONNECTED;
+               goto fail;
+       }
+
+       if (g_slist_length(dev->senders) == 1)
+               goto update;
+       else {
+               param = dev->senders->data;
+
+               BT_DBG("dev %f, param %f, input %f", dev->interval_min, param->interval_min, interval_min);
+
+               if (dev->interval_min == param->interval_min && dev->interval_max == param->interval_max) {
+                       BT_DBG("Skip due to same interval");
+                       return ret;
+               }
+
+               interval_min = param->interval_min;
+               interval_max = param->interval_max;
+       }
+
+update:
+       ret = __bt_le_set_conn_parameter(address, interval_min, interval_max, latency, time_out);
+
+       if (ret != BLUETOOTH_ERROR_NONE) {
+               _bt_remove_le_conn_param_info(address, sender, &is_removed);
+               return ret;
+       }
+
+       dev->interval_min = interval_min;
+       dev->interval_max = interval_max;
+
+fail:
+       return ret;
+}
+
 int _bt_set_pin_code(bluetooth_device_address_t *device_address,
                                bluetooth_device_pin_code_t *pin_code)
 {
index 8fe05a1be3b9bfa038af2ba7cc40337dd1a19060..d3a550e8f0ec3e435a48b7bbb773dbd19fd5c324 100644 (file)
@@ -1618,17 +1618,14 @@ void __bt_gatt_char_property_changed_event(GVariant *msg,
        g_variant_iter_init(&value_iter, msg);
        char_handle = g_strdup(path);
        while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &val))) {
-               BT_INFO("Property %s", property);
+               BT_DBG("Property %s", property);
 
                ret_if(property == NULL);
 
                if (strcasecmp(property, "Notifying") == 0) {
                        gboolean property_flag = FALSE;
                        g_variant_get(val, "b", &property_flag);
-                       if (property_flag == TRUE)
-                               BT_DBG("notifying is enabled");
-                       else
-                               BT_DBG("notifying is disabled");
+                       BT_INFO("Notifying is %s", property_flag ? "enabled" : "disabled");
                } else if (strcasecmp(property, "ChangedValue") == 0) {
                        int len = 0;
                        GByteArray *gp_byte_array = NULL;
@@ -1717,7 +1714,6 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                        gboolean connected = FALSE;
                        char *address;
                        address = g_malloc0(BT_ADDRESS_STRING_SIZE);
-                       ret_if(address == NULL);
 
                        _bt_convert_device_path_to_address(path, address);
                        g_variant_get(msg, "(b)", &connected);
@@ -1750,7 +1746,6 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                        }
 
                        address = g_malloc0(BT_ADDRESS_STRING_SIZE);
-                       ret_if(address == NULL);
 
                        _bt_convert_device_path_to_address(path, address);
 
@@ -1801,7 +1796,6 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                        ret_if(_bt_is_device_creating() == TRUE);
 
                        address = g_malloc0(BT_ADDRESS_STRING_SIZE);
-                       ret_if(address == NULL);
 
                        _bt_convert_device_path_to_address(path, address);
 
@@ -1851,7 +1845,6 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                g_variant_get(msg, "(y)", &addr_type);
 
                address = g_malloc0(BT_ADDRESS_STRING_SIZE);
-               ret_if(address == NULL);
 
                _bt_convert_device_path_to_address(path, address);
                dev_name = _bt_get_bonded_device_name(address);
@@ -1862,6 +1855,9 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                                !addr_type ? dev_name : secure_address);
                g_free(dev_name);
 
+               if (addr_type)
+                       _bt_add_le_connected_dev_info(address);
+
                _bt_logging_connection(TRUE, addr_type);
                param = g_variant_new("(isy)", result, address, addr_type);
                /*Send event to application*/
@@ -1880,7 +1876,6 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                result = disc_reason;
 
                address = g_malloc0(BT_ADDRESS_STRING_SIZE);
-               ret_if(address == NULL);
 
                _bt_convert_device_path_to_address(path, address);
 
@@ -1897,7 +1892,9 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                _bt_headset_set_local_connection(FALSE);
                _bt_logging_connection(FALSE, addr_type);
 
-               if (!addr_type) {
+               if (addr_type)
+                       _bt_remove_le_connected_dev_info(address);
+               else {
 #ifdef TIZEN_BT_A2DP_SINK_AUTO_CONNECT
                        {
                                int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
@@ -1946,7 +1943,6 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                g_variant_get(msg, "(si)", &profile_uuid, &state);
 
                address = g_malloc0(BT_ADDRESS_STRING_SIZE);
-               ret_if(address == NULL);
 
                _bt_convert_device_path_to_address(path, address);
                _bt_convert_addr_string_to_type(bd_addr.addr, address);
@@ -2262,8 +2258,6 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path
                ret_if(_bt_is_le_scanning() == FALSE);
 
                ibeacon_dev_info = g_malloc0(sizeof(bt_remote_ibeacon_dev_info_t));
-               if (ibeacon_dev_info == NULL)
-                       return;
 
                g_variant_get(msg, "(syuusuuy)", &ibeacon_dev_info->address,
                                                &ibeacon_dev_info->addr_type,
@@ -2341,8 +2335,6 @@ void _bt_handle_headset_event(GVariant *msg, const char *path)
                g_variant_get(value, "b", &property_flag);
 
                address = g_malloc0(BT_ADDRESS_STRING_SIZE);
-               if (address == NULL)
-                       return;
 
                _bt_convert_device_path_to_address(path, address);
                _bt_convert_addr_string_to_type(bd_addr.addr, address);
@@ -2849,10 +2841,15 @@ static  void __bt_manager_event_filter(GDBusConnection *connection,
                        _bt_rfcomm_server_check_termination(name);
                }
 
+               /* Reset connection interval */
+               _bt_remove_all_le_conn_param_info(name);
+
                /* Stop advertising started by terminated process */
                _bt_stop_advertising_by_terminated_process(name);
+
                /* Stop LE Scan */
                _bt_stop_le_scan(name);
+
                g_free(name);
                g_free(previous);
                g_free(current);
index 5391e223fbf6d8ab523deb0bb2478d7c3d149f71..d918f86154ef41b0b90f63cf5b9bc4b99f7a88b9 100644 (file)
@@ -88,7 +88,12 @@ int _bt_connect_le_device(int req_id, const bluetooth_device_address_t *bd_addr,
 int _bt_disconnect_le_device(int req_id,
                const bluetooth_device_address_t *bd_addr);
 
-int _bt_le_conn_update(unsigned char *device_address,
+void _bt_add_le_connected_dev_info(const char *address);
+void _bt_remove_le_connected_dev_info(const char *address);
+int _bt_remove_all_le_conn_param_info(const char *sender);
+
+int _bt_le_conn_update(const char *sender,
+                               unsigned char *device_address,
                                float interval_min, float interval_max,
                                guint16 latency, guint16 time_out);