__BEGIN_DECLS
+#ifdef TIZEN_BT_HAL
+#define BT_GATTC_LE_SCAN_TYPE_PASSIVE 0x00
+#define BT_GATTC_LE_SCAN_TYPE_ACTIVE 0x01
+#endif
+
/** Buffer type for unformatted reads/writes */
typedef struct
{
bt_status_t (*scan_filter_enable)(int client_if, bool enable);
/** Sets the LE scan interval and window in units of N*0.625 msec */
+#ifdef TIZEN_BT_HAL
+ bt_status_t (*set_scan_parameters)(int scan_type, int scan_interval, int scan_window);
+#else
bt_status_t (*set_scan_parameters)(int scan_interval, int scan_window);
+#endif
/* Configure the batchscan storage */
bt_status_t (*batchscan_cfg_storage)(int client_if, int batch_scan_full_max,
uint32_t server_instance;
} __attribute__((packed));
+#define HAL_EV_GATT_CLIENT_REGISTERED 0xAA
+struct hal_ev_gatt_client_registered {
+ uint32_t status;
+ uint32_t client_if;
+ uint8_t app_uuid[16];
+} __attribute__((packed));
+
+#define HAL_EV_GATT_CLIENT_SCAN_RESULT 0xAC
+struct hal_ev_gatt_client_scan_result {
+ uint8_t bd_addr[6];
+ uint8_t addr_type;
+ uint8_t adv_type;
+ int32_t rssi;
+ uint16_t len;
+ uint8_t adv_data[0];
+} __attribute__((packed));
+
#endif //_BT_HAL_MSG_H_
#define BT_HAL_MULTI_ADV_UPDATE_EVT 5
#define BT_HAL_LEGACY_ADV_STATUS 6
+handle_stack_msg gatt_le_event_cb;
+
/* Forward declarations */
static gboolean __bt_hal_is_factory_test_mode(void);
static void __bt_hal_free_le_adv_slot(void);
static gboolean __bt_hal_adv_event_cb(gpointer param)
{
- handle_stack_msg event_cb;
bt_hal_adv_event_data_t *event = (bt_hal_adv_event_data_t*)param;
DBG("+");
if (!event)
return FALSE;
- event_cb = _bt_hal_get_gatt_event();
- if (!event_cb) {
+ if (!gatt_le_event_cb) {
ERR("GATT event callback not registered!!!");
return FALSE;
}
memset(&ev, 0, sizeof(struct hal_ev_multi_adv_enable));
ev.status = event->status;
ev.server_instance = event->server_if;
- event_cb(HAL_EV_MULTI_ADV_ENABLE, (void *)&ev, sizeof(ev));
+ gatt_le_event_cb(HAL_EV_MULTI_ADV_ENABLE, (void *)&ev, sizeof(ev));
INFO("BLE Advertising enabled slot [%d]", event->server_if);
break;
}
memset(&ev, 0, sizeof(struct hal_ev_multi_adv_disable));
ev.status = event->status;
ev.server_instance = event->server_if;
- event_cb(HAL_EV_MULTI_ADV_DISABLE, (void *)&ev, sizeof(ev));
+ gatt_le_event_cb(HAL_EV_MULTI_ADV_DISABLE, (void *)&ev, sizeof(ev));
INFO("BLE Advertising disabled slot [%d]", event->server_if);
break;
}
memset(&ev, 0, sizeof(struct hal_ev_multi_adv_update));
ev.status = event->status;
ev.server_instance = event->server_if;
- event_cb(HAL_EV_MULTI_ADV_UPDATE, (void *)&ev, sizeof(ev));
+ gatt_le_event_cb(HAL_EV_MULTI_ADV_UPDATE, (void *)&ev, sizeof(ev));
INFO("BLE Advertising Param update slot [%d]", event->server_if);
break;
}
memset(&ev_data_set, 0, sizeof(struct hal_ev_multi_adv_data_set));
ev_data_set.status = event->status;
ev_data_set.server_instance = event->server_if;
- event_cb(HAL_EV_MULTI_ADV_DATA_SET, (void *)&ev_data_set, sizeof(ev_data_set));
+ gatt_le_event_cb(HAL_EV_MULTI_ADV_DATA_SET, (void *)&ev_data_set, sizeof(ev_data_set));
break;
}
case BT_HAL_LEGACY_ADV_STATUS: {
memset(&ev, 0, sizeof(struct hal_ev_legacy_adv_status));
ev.status = event->status;
ev.server_instance = event->server_if;
- event_cb(HAL_EV_LEGACY_ADV_ENABLE, (void *)&ev, sizeof(ev));
+ gatt_le_event_cb(HAL_EV_LEGACY_ADV_ENABLE, (void *)&ev, sizeof(ev));
break;
}
default:
return BT_STATUS_SUCCESS;
}
+
+int _bt_hal_adapter_le_start_scan(void)
+{
+ GDBusProxy *proxy;
+ GError *error = NULL;
+ GVariant *ret;
+
+ DBG("+");
+
+ /* TODO: Check adapter and LE adapter status */
+ proxy = _bt_get_adapter_proxy();
+ if (proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ ret = g_dbus_proxy_call_sync(proxy, "StartLEDiscovery",
+ NULL, G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+ if (ret == NULL) {
+ if (error) {
+ ERR("StartLEDiscovery Fail: %s", error->message);
+ g_clear_error(&error);
+ }
+
+ return BT_STATUS_FAIL;
+ }
+
+ g_variant_unref(ret);
+
+ DBG("-");
+ return BT_STATUS_SUCCESS;
+}
+
+int _bt_hal_adapter_le_stop_scan(void)
+{
+ GDBusProxy *proxy;
+ GError *error = NULL;
+ GVariant *ret;
+
+ DBG("+");
+
+ /* TODO: Check adapter and LE adapter status */
+ proxy = _bt_get_adapter_proxy();
+ if (proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ ret = g_dbus_proxy_call_sync(proxy, "StopLEDiscovery",
+ NULL, G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+ if (ret == NULL) {
+ if (error) {
+ ERR("StopLEDiscovery Fail: %s", error->message);
+ g_clear_error(&error);
+ }
+
+ return BT_STATUS_FAIL;
+ }
+
+
+ g_variant_unref(ret);
+
+ DBG("-");
+ return BT_STATUS_SUCCESS;
+}
+
+
+int _bt_hal_adapter_le_set_scan_parameters(
+ int scan_type, int scan_interval, int scan_window)
+{
+ GDBusProxy *proxy;
+ GError *error = NULL;
+ GVariant *ret;
+
+ DBG("+");
+
+ /* TODO: Check adapter and LE adapter status */
+ proxy = _bt_get_adapter_proxy();
+ if (proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ ret = g_dbus_proxy_call_sync(proxy, "SetScanParameters",
+ g_variant_new("(uuu)", scan_type, scan_interval, scan_window),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+ if (ret == NULL) {
+ if (error) {
+ ERR("SetScanParameters Fail: %s", error->message);
+ g_clear_error(&error);
+ }
+
+ return BT_STATUS_FAIL;
+ }
+
+ g_variant_unref(ret);
+
+ DBG("-");
+ return BT_STATUS_SUCCESS;
+}
+
+/* To send stack event to hal-av handler */
+void _bt_hal_register_gatt_le_dbus_handler_cb(handle_stack_msg cb)
+{
+ gatt_le_event_cb = cb;
+}
+
+void _bt_hal_unregister_gatt_le_dbus_handler_cb(void)
+{
+ gatt_le_event_cb = NULL;
+}
#include <hardware/bt_gatt_server.h>
+#include "bt-hal-event-receiver.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+void _bt_hal_register_gatt_le_dbus_handler_cb(handle_stack_msg cb);
+
+void _bt_hal_unregister_gatt_le_dbus_handler_cb();
+
gboolean _bt_hal_update_le_feature_support(const char *item, const char *value);
int _bt_hal_get_available_adv_slot_id(bt_uuid_t *uuid);
int _bt_hal_enable_advertising(int server_if, bool enable, bool is_multi_adv);
+int _bt_hal_adapter_le_start_scan(void);
+
+int _bt_hal_adapter_le_stop_scan(void);
+
+int _bt_hal_adapter_le_set_scan_parameters(
+ int scan_type, int scan_interval, int scan_window);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
static void __bt_hal_handle_headset_events(GVariant *msg, const char *member,const char *path);
static void __bt_hal_send_hf_audio_connection_state_event(gboolean connected, const char *address);
+static void __bt_hal_handle_adv_report(GVariant *msg, const char *path);
+
static gboolean __bt_hal_discovery_finished_cb(gpointer user_data)
{
event_id = 0;
}
} else if (!g_strcmp0(key, "LEDiscovering")) {
+ GVariant *result;
+
is_le_discovering = g_variant_get_boolean(value);
DBG("##LE Discovering = [%d]", is_le_discovering);
+
+ if (is_le_discovering)
+ continue;
+
+ adapter_proxy = _bt_get_adapter_proxy();
+ if (adapter_proxy == NULL) {
+ ERR("adapter_proxy == NULL");
+ continue;
+ }
+
+ /* Need to stop searching */
+ result = g_dbus_proxy_call_sync(adapter_proxy, "StopLEDiscovery",
+ NULL, G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT, NULL, &err);
+ if (!result) {
+ ERR("Error occured in Proxy call");
+ if (err) {
+ ERR("(Error: %s)", err->message);
+ g_clear_error(&err);
+ }
+ continue;
+ }
+ g_variant_unref(result);
} else if (!g_strcmp0(key, "Modalias")) {
char *modalias = NULL;
g_variant_get(value, "s", &modalias);
g_free(address);
g_free(profile_uuid);
} else if (strcasecmp(member, "AdvReport") == 0) {
- /* TODO */
DBG("Member: [%s]", member);
+ __bt_hal_handle_adv_report(msg, path);
+ }
+}
+
+static void __bt_hal_handle_adv_report(GVariant *msg, const char *path)
+{
+ uint8_t buf[BT_HAL_MAX_PROPERTY_BUF_SIZE];
+ struct hal_ev_gatt_client_scan_result *ev = (void *)buf;
+ size_t size = 0;
+ char *address = NULL;
+ GVariant *value = NULL;
+ char *buffer = NULL;
+ int data_len = 0;
+ int buffer_len = 0;
+ uint8_t addr_type = 0;
+ uint8_t adv_type = 0;
+ int rssi = 0;
+
+ if (!gatt_event_cb)
+ return;
+
+ memset(buf, 0, sizeof(buf));
+ size = sizeof(*ev);
+
+ g_variant_get(msg, "(&syyii@ay)", &address, &addr_type,
+ &adv_type, &rssi, &data_len, &value);
+
+ buffer_len = g_variant_get_size(value);
+ if (buffer_len > 0)
+ buffer = (char *)g_variant_get_data(value);
+
+ if (data_len != buffer_len) {
+ ERR("Unexpected: buffer_len: %d, data_len: %d",
+ buffer_len, data_len);
+ data_len = buffer_len;
}
+
+ DBG("Address: %s, len: %d, rssi: %d, addr_type: 0x%02X, adv_type: 0x%02X",
+ address, data_len, rssi, addr_type, adv_type);
+
+ _bt_convert_addr_string_to_type(ev->bd_addr, address);
+ ev->addr_type = addr_type;
+ ev->adv_type = adv_type;
+ ev->rssi = rssi;
+ ev->len = data_len;
+ memcpy(ev->adv_data, buffer, data_len);
+ size += data_len;
+
+ DBG("Send le scan result event to HAL, size: [%d]", size);
+ gatt_event_cb(HAL_EV_GATT_CLIENT_SCAN_RESULT, buf, size);
+ g_variant_unref(value);
}
/* AVRCP Controller Role(Remote:AVRCP Target) Events */
#include <stdlib.h>
#include <errno.h>
#include <string.h>
+#include <dlog.h>
+
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+#include "bt-hal-event-receiver.h"
+#include "bt-hal-adapter-le.h"
+
+#include "bt-hal-gatt-client.h"
+
+/************************************************************************************
+ ** Static variables
+ ************************************************************************************/
+extern const btgatt_callbacks_t *bt_gatt_callbacks;
+#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\
+{\
+ ERR("%s: BTGATT not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+} else {\
+ DBG("%s", __FUNCTION__);\
+}
+
+typedef struct {
+ uint32_t client_if;
+ bt_uuid_t uuid;
+} hal_registered_client_t;
+
+#ifdef TIZEN_BT_HAL
+int le_scan_type = BT_GATTC_LE_SCAN_TYPE_PASSIVE;
+#endif
+
+static handle_stack_msg event_cb = NULL;
+
+/* To send stack event to hal-av handler */
+void _bt_hal_register_gatt_client_handler_cb(handle_stack_msg cb)
+{
+ event_cb = cb;
+}
+
+void _bt_hal_unregister_gatt_client_handler_cb(void)
+{
+ event_cb = NULL;
+}
+
+#ifdef TIZEN_BT_HAL
+int _bt_hal_gatt_client_get_le_scan_type(void)
+{
+ return le_scan_type;
+}
+#endif
+
+static gboolean __bt_hal_register_client_cb(gpointer user_data)
+{
+ struct hal_ev_gatt_client_registered ev;
+ hal_registered_client_t *client_info = user_data;
+
+ /* Prepare to send AV connecting event */
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_STATUS_SUCCESS;
+ ev.client_if = client_info->client_if;
+ memcpy(ev.app_uuid, client_info->uuid.uu, sizeof(ev.app_uuid));
+
+ if (!event_cb)
+ ERR("GATT Callback not registered");
+ else {
+ DBG("GATT client registered, client_if: [%d]", client_info->client_if);
+ event_cb(HAL_EV_GATT_CLIENT_REGISTERED, (void *)&ev, sizeof(ev));
+ }
+
+ g_free(user_data);
+ return FALSE;
+}
+
+/** Registers a GATT client application with the stack */
+bt_status_t register_client(bt_uuid_t *uuid)
+{
+ hal_registered_client_t *client_info = NULL;
+
+ client_info = g_malloc0(sizeof(hal_registered_client_t));
+ /*
+ * TODO: Actual client_if will be used here later when GATT register_client
+ * is implemented compeltely. For now return 1 as client_if.
+ */
+ client_info->client_if = 1;
+ memcpy(client_info->uuid.uu, uuid->uu, sizeof(bt_uuid_t));
+
+ /*
+ * As we need to provide async callback to user from HAL, simply schedule a
+ * callback method which will carry actual result
+ */
+ g_idle_add(__bt_hal_register_client_cb, (gpointer)client_info);
+
+ /* If available, then return success, else return error */
+ return BT_STATUS_SUCCESS;
+}
+
+/* TODO: APIs will be implemented in subsequent patches whenever required */
+/** Unregister a client application from the stack */
+bt_status_t unregister_client(int client_if)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Start or stop LE device scanning */
+bt_status_t scan(int client_if, bool start)
+{
+ int ret;
+
+ CHECK_BTGATT_INIT();
+
+ if (start)
+ ret = _bt_hal_adapter_le_start_scan();
+ else
+ ret = _bt_hal_adapter_le_stop_scan();
+
+ return ret;
+}
+
+/** Create a connection to a remote LE or dual-mode device */
+bt_status_t connect(int client_if, const bt_bdaddr_t *bd_addr,
+ bool is_direct)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Disconnect a remote device or cancel a pending connection */
+bt_status_t disconnect(int client_if, const bt_bdaddr_t *bd_addr,
+ int conn_id)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Clear the attribute cache for a given device */
+bt_status_t refresh(int client_if, const bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * Enumerate all GATT services on a connected device.
+ * Optionally, the results can be filtered for a given UUID.
+ */
+bt_status_t search_service(int conn_id, bt_uuid_t *filter_uuid)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * Enumerate included services for a given service.
+ * Set start_incl_srvc_id to NULL to get the first included service.
+ */
+bt_status_t get_included_service(int conn_id, btgatt_srvc_id_t *srvc_id,
+ btgatt_srvc_id_t *start_incl_srvc_id)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * Enumerate characteristics for a given service.
+ * Set start_char_id to NULL to get the first characteristic.
+ */
+bt_status_t get_characteristic(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * Enumerate descriptors for a given characteristic.
+ * Set start_descr_id to NULL to get the first descriptor.
+ */
+bt_status_t get_descriptor(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *start_descr_id)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Read a characteristic on a remote device */
+bt_status_t read_characteristic(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ int auth_req)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Write a remote characteristic */
+bt_status_t write_characteristic(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ int write_type, int len, int auth_req,
+ char* p_value)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Read the descriptor for a given characteristic */
+bt_status_t read_descriptor(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *descr_id, int auth_req)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+/** Write a remote descriptor for a given characteristic */
+bt_status_t write_descriptor(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *descr_id, int write_type, int len,
+ int auth_req, char* p_value)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Execute a prepared write operation */
+bt_status_t execute_write(int conn_id, int execute)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * Register to receive notifications or indications for a given
+ * characteristic
+ */
+bt_status_t register_for_notification(int client_if,
+ const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+ btgatt_gatt_id_t *char_id)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Deregister a previous request for notifications/indications */
+bt_status_t deregister_for_notification(int client_if,
+ const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+ btgatt_gatt_id_t *char_id)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Request RSSI for a given remote device */
+bt_status_t read_remote_rssi(int client_if, const bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** OTA firmware download */
+bt_status_t ota_fw_update(int client_if, int conn_id, const bt_bdaddr_t *bd_addr, char* path)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Determine the type of the remote device (LE, BR/EDR, Dual-mode) */
+int get_device_type(const bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Request a connection parameter update */
+bt_status_t conn_parameter_update(bt_bdaddr_t *bd, int min_int, int max_int, int latency, int timeout)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Test mode interface */
+bt_status_t test_command(int command, btgatt_test_params_t* params)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** MTU Exchange request from client */
+bt_status_t configure_mtu(int conn_id, int mtu)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Setup scan filter params */
+bt_status_t scan_filter_param_setup(int client_if, int action, int filt_index, int feat_seln,
+ int list_logic_type, int filt_logic_type, int rssi_high_thres,
+ int rssi_low_thres, int dely_mode, int found_timeout,
+ int lost_timeout, int found_timeout_cnt)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+
+/** Configure a scan filter condition */
+bt_status_t scan_filter_add_remove(int client_if, int action, int filt_type,
+ int filt_index, int company_id,
+ int company_id_mask, const bt_uuid_t *p_uuid,
+ const bt_uuid_t *p_uuid_mask, const bt_bdaddr_t *bd_addr,
+ char addr_type, int data_len, char* p_data, int mask_len,
+ char* p_mask)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Clear all scan filter conditions for specific filter index*/
+bt_status_t scan_filter_clear(int client_if, int filt_index)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Enable / disable scan filter feature*/
+bt_status_t scan_filter_enable(int client_if, bool enable)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/** Sets the LE scan interval and window in units of N*0.625 msec */
+#ifdef TIZEN_BT_HAL
+bt_status_t set_scan_parameters(int scan_type, int scan_interval, int scan_window)
+{
+ int ret;
+
+ CHECK_BTGATT_INIT();
+
+ le_scan_type = scan_type;
+ ret = _bt_hal_adapter_le_set_scan_parameters(
+ scan_type, scan_interval, scan_window);
+ return ret;
+}
+#else
+bt_status_t set_scan_parameters(int scan_interval, int scan_window)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+#endif
+
+/* Configure the batchscan storage */
+bt_status_t batchscan_cfg_storage(int client_if, int batch_scan_full_max,
+ int batch_scan_trunc_max, int batch_scan_notify_threshold)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/* Enable batchscan */
+bt_status_t batchscan_enb_batch_scan(int client_if, int scan_mode,
+ int scan_interval, int scan_window, int addr_type, int discard_rule)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/* Disable batchscan */
+bt_status_t batchscan_dis_batch_scan(int client_if)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/* Read out batchscan reports */
+bt_status_t batchscan_read_reports(int client_if, int scan_mode)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_UNSUPPORTED;
+}
-/*TODO*/
const btgatt_client_interface_t btgatt_client_interface = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ register_client,
+ unregister_client,
+ scan,
+ connect,
+ disconnect,
+ refresh,
+ search_service,
+ get_included_service,
+ get_characteristic,
+ get_descriptor,
+ read_characteristic,
+ write_characteristic,
+ read_descriptor,
+ write_descriptor,
+ execute_write,
+ register_for_notification,
+ deregister_for_notification,
+ read_remote_rssi,
+ ota_fw_update,
+ get_device_type,
+ conn_parameter_update,
+ test_command,
+ configure_mtu,
+ scan_filter_param_setup,
+ scan_filter_add_remove,
+ scan_filter_clear,
+ scan_filter_enable,
+ set_scan_parameters,
+ batchscan_cfg_storage,
+ batchscan_enb_batch_scan,
+ batchscan_dis_batch_scan,
+ batchscan_read_reports
};
--- /dev/null
+/*
+ * BLUETOOOTH HAL
+ *
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Atul Rai <a.rai@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _BT_HAL_GATT_CLIENT_H_
+#define _BT_HAL_GATT_CLIENT_H_
+
+#include <glib.h>
+#include <sys/types.h>
+
+#include "bt-hal.h"
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+
+#include "bt-hal-event-receiver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _bt_hal_register_gatt_client_handler_cb(handle_stack_msg cb);
+void _bt_hal_unregister_gatt_client_handler_cb(void);
+
+#ifdef TIZEN_BT_HAL
+int _bt_hal_gatt_client_get_le_scan_type(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /*_BT_HAL_GATT_CLIENT_H_*/
/* To send stack event to hal-av handler */
void _bt_hal_register_gatt_server_handler_cb(handle_stack_msg cb)
{
- event_cb = cb;
+ event_cb = cb;
}
-handle_stack_msg _bt_hal_get_gatt_event(void)
+void _bt_hal_unregister_gatt_server_handler_cb(void)
{
- return event_cb;
+ event_cb = NULL;
}
static gboolean __bt_hal_register_slot_id_cb(gpointer user_data)
}
/*
- * As we need to provide async callback to user from HAL, simply schedule a
- * callback method which will carry actual result
- */
+ * As we need to provide async callback to user from HAL, simply schedule a
+ * callback method which will carry actual result
+ */
memcpy(user_data->uuid.uu, uuid->uu, sizeof(bt_uuid_t));
- g_idle_add(__bt_hal_register_slot_id_cb, (gpointer)user_data);
+ g_idle_add(__bt_hal_register_slot_id_cb, (gpointer)user_data);
/* If available, then return success, else return error */
return BT_STATUS_SUCCESS;
DBG("+");
/* Send Advertising parameters to LE Module */
return _bt_hal_set_advertising_params(server_if, min_interval, max_interval, adv_type,
- chnl_map, tx_power, timeout_s);
+ chnl_map, tx_power, timeout_s);
}
static bt_status_t gatt_server_multi_adv_set_inst_data(btgatt_adv_param_setup_t adv_param_setup)
void _bt_hal_register_gatt_server_handler_cb(handle_stack_msg cb);
-handle_stack_msg _bt_hal_get_gatt_event(void);
+void _bt_hal_unregister_gatt_server_handler_cb(void);
#ifdef __cplusplus
}
*
* Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Anupam Roy <anupam.r@samsung.com>
+ * Contact: Anupam Roy <anupam.r@samsung.com>
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
*/
/*******************************************************************************
*
- * Filename: btif_gatt.c
+ * Filename: btif_gatt.c
*
- * Description: GATT Profile Bluetooth Interface
+ * Description: GATT Profile Bluetooth Interface
*
*******************************************************************************/
#include "bt-hal-msg.h"
#include "bt-hal-utils.h"
+#include "bt-hal-adapter-le.h"
#include "bt-hal-gatt-server.h"
+#include "bt-hal-gatt-client.h"
+/* Advertising report event types */
+#define BT_LE_ADV_IND 0x00
+#define BT_LE_ADV_DIRECT_IND 0x01
+#define BT_LE_ADV_SCAN_IND 0x02
+#define BT_LE_ADV_NONCONN_IND 0x03
+#define BT_LE_ADV_SCAN_RSP 0x04
+
+#define BT_HAL_ADV_DATA_MAX_SIZE 31
+typedef struct {
+ char addr[18];
+ uint8_t addr_type;
+ uint8_t adv_type;
+ int rssi;
+ int data_len;
+ uint8_t data[BT_HAL_ADV_DATA_MAX_SIZE * 2];
+ guint timer_id;
+} bt_hal_le_adv_info_t;
+
+/****************************************** Global Variables ******************************************/
const btgatt_callbacks_t *bt_gatt_callbacks = NULL;
extern btgatt_client_interface_t btgatt_client_interface;
extern btgatt_server_interface_t btgatt_server_interface;
+static GSList *adv_ind_list = NULL;
+/****************************************** Forward Declarations *************************************/
+static void __bt_handle_gatt_client_registered(void *buf, uint16_t len);
+static void __bt_hal_handle_gatt_client_scan_result(void *buf, uint16_t len);
+/*****************************************************************************************************/
+
static bool interface_ready(void)
{
- return bt_gatt_callbacks != NULL;
+ return bt_gatt_callbacks != NULL;
}
static void __bt_hal_handle_server_instance_initialized(void *buf, uint16_t len)
__bt_hal_handle_legacy_adv_status(buf, len);
break;
}
+ case HAL_EV_GATT_CLIENT_REGISTERED: {
+ __bt_handle_gatt_client_registered(buf, len);
+ break;
+ }
+ case HAL_EV_GATT_CLIENT_SCAN_RESULT: {
+ __bt_hal_handle_gatt_client_scan_result(buf, len);
+ break;
+ }
default:
DBG("Event Currently not handled!!");
break;
DBG("-");
}
+/************************************* GATT CLIENT EVENTS ****************************************/
+static void __bt_handle_gatt_client_registered(void *buf, uint16_t len)
+{
+ struct hal_ev_gatt_client_registered *ev = buf;
+ bt_uuid_t uuid;
+
+ memcpy(uuid.uu, ev->app_uuid, 16);
+ if (bt_gatt_callbacks->client->register_client_cb)
+ bt_gatt_callbacks->client->register_client_cb(
+ ev->status, ev->client_if, &uuid);
+}
+
+static void __bt_hal_send_le_scan_result_event(bt_hal_le_adv_info_t *adv_info)
+{
+ bt_bdaddr_t bd_addr;
+
+ str2bt_bdaddr_t(adv_info->addr, &bd_addr);
+ if (bt_gatt_callbacks->client->scan_result_cb)
+ bt_gatt_callbacks->client->scan_result_cb(
+ &bd_addr, adv_info->rssi, adv_info->data);
+}
+
+static bt_hal_le_adv_info_t *__bt_hal_get_adv_ind_info(char *addr)
+{
+ GSList *l;
+
+ if (!addr)
+ return NULL;
+
+ for (l = adv_ind_list; NULL != l; l = g_slist_next(l)) {
+ bt_hal_le_adv_info_t *adv_info = l->data;
+
+ if (!adv_info)
+ continue;
+
+ if (!g_strcmp0(adv_info->addr, addr))
+ return adv_info;
+ }
+
+ return NULL;
+}
+
+static int __bt_hal_add_adv_ind_info(bt_hal_le_adv_info_t *adv_info)
+{
+ if (!adv_info)
+ return -1;
+
+ if (__bt_hal_get_adv_ind_info(adv_info->addr) != NULL) {
+ DBG("Adv info already present");
+ return -1;
+ }
+
+ adv_ind_list = g_slist_append(adv_ind_list, adv_info);
+ return 0;
+}
+
+static gboolean __bt_hal_adv_scan_req_timeout_cb(gpointer user_data)
+{
+ bt_hal_le_adv_info_t *adv_info = user_data;
+
+ __bt_hal_send_le_scan_result_event(adv_info);
+ adv_ind_list = g_slist_remove(adv_ind_list, adv_info);
+ g_free(adv_info);
+ return FALSE;
+}
+
+static void __bt_hal_handle_gatt_client_scan_result(void *buf, uint16_t len)
+{
+ bt_bdaddr_t bd_addr;
+ char address[18];
+ struct hal_ev_gatt_client_scan_result *ev = buf;
+ bt_hal_le_adv_info_t *adv_info;
+ int data_len = 0;
+
+ memcpy(bd_addr.address, ev->bd_addr, 6);
+ bt_bdaddr_t2str(&bd_addr, address);
+ data_len = (ev->len < BT_HAL_ADV_DATA_MAX_SIZE) ? ev->len : BT_HAL_ADV_DATA_MAX_SIZE;
+ if (data_len == 0 && ev->adv_type != BT_LE_ADV_SCAN_RSP) {
+ ERR("Unexpected: Data len is 0");
+ return;
+ }
+
+ if (ev->adv_type == BT_LE_ADV_SCAN_RSP) { /* SCAN_RSP */
+ adv_info = __bt_hal_get_adv_ind_info(address);
+ if (adv_info) {
+ /* Copy scan response data in data field and send event */
+ memcpy(&(adv_info->data[adv_info->data_len]), ev->adv_data, data_len);
+ __bt_hal_send_le_scan_result_event(adv_info);
+ adv_ind_list = g_slist_remove(adv_ind_list, adv_info);
+ if (adv_info->timer_id)
+ g_source_remove(adv_info->timer_id);
+ g_free(adv_info);
+ }
+ return;
+ }
+
+ /* ADV_IND */
+ adv_info = g_malloc0(sizeof(bt_hal_le_adv_info_t));
+ if (!adv_info) {
+ ERR("Not enough memory");
+ return;
+ }
+
+ g_strlcpy(adv_info->addr, address, 18);
+ adv_info->addr_type = ev->addr_type;
+ adv_info->adv_type = ev->adv_type;
+ adv_info->rssi = ev->rssi;
+ adv_info->data_len = data_len;
+ memcpy(adv_info->data, ev->adv_data, data_len);
+
+#ifdef TIZEN_BT_HAL
+ if (_bt_hal_gatt_client_get_le_scan_type() == BT_GATTC_LE_SCAN_TYPE_PASSIVE) {
+ __bt_hal_send_le_scan_result_event(adv_info);
+ g_free(adv_info);
+ return;
+ }
+#endif
+ if (__bt_hal_add_adv_ind_info(adv_info))
+ adv_info->timer_id = g_timeout_add(1000,
+ __bt_hal_adv_scan_req_timeout_cb,
+ (void *)adv_info);
+}
+
/*******************************************************************************
-**
-** Function gatt_init
-**
-** Description Initializes the GATT interface
-**
-** Returns bt_status_t
-**
-*******************************************************************************/
+ **
+ ** Function gatt_init
+ **
+ ** Description Initializes the GATT interface
+ **
+ ** Returns bt_status_t
+ **
+ *******************************************************************************/
static bt_status_t gatt_init(const btgatt_callbacks_t* callbacks )
{
bt_gatt_callbacks = callbacks;
DBG("Register A2DP Src events callback function");
+ _bt_hal_register_gatt_le_dbus_handler_cb(__bt_hal_gatt_events);
_bt_hal_register_gatt_server_handler_cb(__bt_hal_gatt_events);
+ _bt_hal_register_gatt_client_handler_cb(__bt_hal_gatt_events);
+ _bt_hal_register_event_handler_cb(HAL_GATT, __bt_hal_gatt_events);
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
-**
-** Function gatt_cleanup
-**
-** Description Closes the GATT interface
-**
-** Returns void
-**
-*******************************************************************************/
-static void gatt_cleanup(void)
+ **
+ ** Function gatt_cleanup
+ **
+ ** Description Closes the GATT interface
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void gatt_cleanup(void)
{
- if (bt_gatt_callbacks)
- bt_gatt_callbacks = NULL;
+ _bt_hal_unregister_gatt_le_dbus_handler_cb();
+ _bt_hal_unregister_gatt_client_handler_cb();
+ _bt_hal_unregister_event_handler_cb(HAL_GATT);
+
+ if (bt_gatt_callbacks)
+ bt_gatt_callbacks = NULL;
}
static const btgatt_interface_t btgatt_interface = {
- sizeof(btgatt_interface),
+ sizeof(btgatt_interface),
- gatt_init,
- gatt_cleanup,
+ gatt_init,
+ gatt_cleanup,
- &btgatt_client_interface,
- &btgatt_server_interface,
+ &btgatt_client_interface,
+ &btgatt_server_interface,
};
/*******************************************************************************
-**
-** Function bt_get_gatt_interface
-**
-** Description Get the gatt callback interface
-**
-** Returns btgatt_interface_t
-**
-*******************************************************************************/
+ **
+ ** Function bt_get_gatt_interface
+ **
+ ** Description Get the gatt callback interface
+ **
+ ** Returns btgatt_interface_t
+ **
+ *******************************************************************************/
const btgatt_interface_t *bt_get_gatt_interface()
{
- return &btgatt_interface;
+ return &btgatt_interface;
}