gatt client adaptation feature changes bt-api bt-service OAL
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / device / bt-service-core-device.c
index 2955a8d..58b7518 100644 (file)
 #endif
 #include "bt-service-device-internal.h"
 
+#ifdef TIZEN_GATT_CLIENT
+#include "bt-service-gatt.h"
+#endif
+
 /* OAL headers */
 #include <oal-event.h>
 #include <oal-manager.h>
@@ -120,6 +124,36 @@ static int bond_retry_count;
 static char *passkey_watcher;
 static GSList *pin_info_list = NULL;
 
+#ifdef TIZEN_GATT_CLIENT
+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;
+
+static GSList *le_connected_dev_list = NULL;
+
+#define BT_LE_CONN_INTERVAL_MIN 7.5 /* msec */
+#define BT_LE_CONN_INTERVAL_MAX 4000 /* msec */
+#define BT_LE_CONN_SUPER_TO_MIN 100 /* msec */
+#define BT_LE_CONN_SUPER_TO_MAX 32000 /* msec */
+#define BT_LE_CONN_SLAVE_LATENCY_MAX 499
+#define BT_LE_CONN_TO_SPLIT 10 /* msec */
+#define BT_LE_CONN_INTERVAL_SPLIT 1.25 /* msec */
+
+static void _bt_handle_le_connected_dev_info(const char *address, gboolean connected);
+#endif
+
 /* Forward declaration */
 static void __bt_device_event_handler(int event_type, gpointer event_data);
 static void __bt_device_remote_device_found_callback(gpointer event_data, gboolean is_ble);
@@ -1337,6 +1371,14 @@ static void __bt_device_conn_state_changed_callback(event_dev_conn_status_t *acl
        /* Update local cache */
        _bt_update_remote_dev_property(address, DEV_PROP_CONNECTED, (void *)&conn_info);
 
+#ifdef TIZEN_GATT_CLIENT
+       /*handle LE connected device info*/
+       if (type) {
+               BT_DBG("handle LE connected device info");
+               _bt_handle_le_connected_dev_info(address, connected);
+       }
+#endif
+
        BT_DBG("-");
 }
 
@@ -1916,6 +1958,10 @@ gboolean _bt_is_device_connected(bluetooth_device_address_t *device_address, int
        case BT_PROFILE_CONN_HSP:
                svc_id = HFP_HS_SERVICE_ID; /* Remote is HFP HF Unit */
                break;
+#ifdef TIZEN_GATT_CLIENT
+       case BT_PROFILE_CONN_GATT:
+               return _bt_is_remote_gatt_device_connected(device_address); /* Remote is GATT client or Server */
+#endif
        default:
                BT_DBG("Unknown svc_type: %d", svc_type);
                return FALSE;
@@ -2100,3 +2146,287 @@ int _bt_unset_pin_code(bluetooth_device_address_t *device_address)
        BT_DBG("-");
        return BLUETOOTH_ERROR_NONE;
 }
+
+#ifdef TIZEN_GATT_CLIENT
+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 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 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;
+}
+
+static 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;
+}
+
+
+static void _bt_handle_le_connected_dev_info(const char *address, gboolean connected)
+{
+       BT_DBG("+");
+
+       if (connected)
+               _bt_add_le_connected_dev_info(address);
+       else
+               _bt_remove_le_connected_dev_info(address);
+}
+
+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;
+}
+
+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;
+}
+
+
+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;
+
+       BT_DBG("+");
+
+       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;
+}
+
+
+static int __bt_le_set_conn_parameter(const char *address,
+               float interval_min, float interval_max,
+               guint16 latency, guint16 time_out)
+{
+       bt_address_t dev_addr = { {0} };
+       guint32 min, max, to;
+
+       BT_INFO("Min interval: %f, Max interval: %f, Latency: %u, Supervision timeout: %u",
+                       interval_min, interval_max, latency, time_out);
+
+       min = interval_min / BT_LE_CONN_INTERVAL_SPLIT;
+       max = interval_max / BT_LE_CONN_INTERVAL_SPLIT;
+       to = time_out / BT_LE_CONN_TO_SPLIT;
+
+       BT_INFO("updating: Min interval: %d, Max interval: %d, Latency: %d, Supervision timeout: %d",
+                       min, max, latency, to);
+
+       _bt_convert_addr_string_to_type(dev_addr.addr, address);
+
+       return gattc_conn_param_update(&dev_addr, min, max, latency, to);
+}
+
+int _bt_remove_le_conn_param_info(const char *address, const char *sender)
+{
+       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);
+       }
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+
+int _bt_le_connection_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;
+       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) {
+               BT_DBG("device not found in the list");
+               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 != OAL_STATUS_SUCCESS) {
+               _bt_remove_le_conn_param_info(address, sender);
+               BT_DBG("fail to update the LE connection parameter");
+               ret = BLUETOOTH_ERROR_INTERNAL;
+               goto fail;
+       }
+
+       BT_DBG("updated LE connection parameter");
+       dev->interval_min = interval_min;
+       dev->interval_max = interval_max;
+
+       return BLUETOOTH_ERROR_NONE;
+fail:
+       return ret;
+}
+
+#endif