#define BT_ADV_FILTER_POLICY_DEFAULT 0x00
#define BT_ADV_TYPE_DEFAULT 0x00
#define BT_ADV_FILTER_POLICY_ALLOW_SCAN_CONN_WL_ONLY 0x03
-#define BT_ADV_MULTI_MAX 16
typedef struct {
int adv_inst_max;
char *sender;
GSList *filter_list;
gboolean is_scanning;
+ gboolean stop_pending;
} bt_adapter_le_scanner_t;
static bluetooth_advertising_params_t adv_params = {
for (i = 0; i < le_feature_info.adv_inst_max; i++) {
if (le_adv_slot[i].sender)
g_free(le_adv_slot[i].sender);
+ if (le_adv_slot[i].hold_timer_id > 0)
+ g_source_remove(le_adv_slot[i].hold_timer_id);
}
g_free(le_adv_slot);
le_adv_slot = NULL;
}
-int _bt_service_adapter_le_init(void)
+int _bt_le_set_max_packet_len(void)
{
- le_adv_slot = g_malloc0(sizeof(bt_adapter_le_adv_slot_t) * le_feature_info.adv_inst_max);
+ int result = BLUETOOTH_ERROR_NONE;
+ int tx_octets, tx_time;
+ bluetooth_le_read_maximum_data_length_t max_len = {0};
- return BLUETOOTH_ERROR_NONE;
-}
+ if (BLUETOOTH_ERROR_NONE != _bt_le_read_maximum_data_length(&max_len))
+ return BLUETOOTH_ERROR_INTERNAL;
-void _bt_service_adapter_le_deinit(void)
-{
- __bt_free_le_adv_slot();
+ if (max_len.max_tx_octets > BT_LE_TX_LEN_DEFAULT) {
+ tx_octets = max_len.max_tx_octets > BT_LE_TX_LEN_MAX ?
+ BT_LE_TX_LEN_MAX : max_len.max_tx_octets;
+ tx_time = BT_LE_TX_TIME_MAX;
+
+ result = _bt_le_write_host_suggested_default_data_length(tx_octets, tx_time);
+
+ BT_DBG("Wrote max packet size : result[%d], MAX[%d], set[%d]",
+ result, max_len.max_tx_octets, tx_octets);
+ }
+
+ return result;
}
gboolean _bt_update_le_feature_support(const char *item, const char *value)
if (item == NULL || value == NULL)
return FALSE;
+ if (!le_adv_slot)
+ _bt_service_adapter_le_init();
+
if (g_strcmp0(item, "adv_inst_max") == 0) {
int slot_num;
slot_num = atoi(value);
retv_if(slot_num < 0, FALSE);
- retv_if(slot_num > BT_ADV_MULTI_MAX, FALSE);
if (slot_num != le_feature_info.adv_inst_max) {
__bt_free_le_adv_slot();
void _bt_unregister_adv_slot_owner(int slot_id)
{
+ if (le_adv_slot[slot_id].hold_timer_id > 0) {
+ BT_INFO("Hold state adv is not unregistered");
+ return;
+ }
+
g_free(le_adv_slot[slot_id].sender);
le_adv_slot[slot_id].sender = NULL;
le_adv_slot[slot_id].adv_handle = 0;
gboolean status = FALSE;
int i;
+ if (le_adv_slot == NULL)
+ return FALSE;
+
for (i = 0; i < le_feature_info.adv_inst_max; i++) {
if (le_adv_slot[i].is_advertising == TRUE)
status = TRUE;
if (le_adv_slot[slot_id].is_advertising == TRUE && enable == TRUE)
return BLUETOOTH_ERROR_IN_PROGRESS;
- if (le_adv_slot[slot_id].sender != NULL && le_adv_slot[slot_id].is_advertising == FALSE && enable == FALSE)
- return BLUETOOTH_ERROR_NOT_IN_OPERATION;
-
if (le_adv_slot[slot_id].hold_timer_id > 0) {
g_source_remove(le_adv_slot[slot_id].hold_timer_id);
le_adv_slot[slot_id].hold_timer_id = 0;
+ _bt_unregister_adv_slot_owner(slot_id);
}
+ if (le_adv_slot[slot_id].is_advertising == FALSE && enable == FALSE)
+ return BLUETOOTH_ERROR_NOT_IN_OPERATION;
+
proxy = _bt_get_adapter_proxy();
retv_if(proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
__bt_register_adv_slot_owner(sender, adv_handle, slot_id);
le_adv_slot[slot_id].is_advertising = enable;
- BT_INFO_C("### Set advertising [%d]", enable);
+ BT_INFO_C("### Set advertising [%d], Slot id [%d]", enable, slot_id);
if (ret)
g_variant_unref(ret);
if (le_adv_slot[slot_id].is_advertising == TRUE && enable == TRUE)
return BLUETOOTH_ERROR_IN_PROGRESS;
- if (le_adv_slot[slot_id].sender != NULL && le_adv_slot[slot_id].is_advertising == FALSE && enable == FALSE)
- return BLUETOOTH_ERROR_NOT_IN_OPERATION;
-
if (le_adv_slot[slot_id].hold_timer_id > 0) {
g_source_remove(le_adv_slot[slot_id].hold_timer_id);
le_adv_slot[slot_id].hold_timer_id = 0;
+ _bt_unregister_adv_slot_owner(slot_id);
}
+ if (le_adv_slot[slot_id].is_advertising == FALSE && enable == FALSE)
+ return BLUETOOTH_ERROR_NOT_IN_OPERATION;
+
proxy = _bt_get_adapter_proxy();
retv_if(proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
params->type == BLUETOOTH_ADV_NON_CONNECTABLE)
return BLUETOOTH_ERROR_NOT_SUPPORT;
+ if (params->tx_power_level > 1 ||
+ params->tx_power_level < -127)
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+
min = params->interval_min / BT_ADV_INTERVAL_SPLIT;
max = params->interval_max / BT_ADV_INTERVAL_SPLIT;
ret = g_dbus_proxy_call_sync(proxy, "SetAdvertisingParameters",
- g_variant_new("(uuuui)", min, max,
+ g_variant_new("(uuuuii)", min, max,
params->filter_policy, params->type,
- slot_id), G_DBUS_CALL_FLAGS_NONE,
- -1, NULL, &error);
+ params->tx_power_level, slot_id),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
if (error) {
BT_ERR("SetAdvertisingParameters Fail: %s", error->message);
adv_params.interval_max = params->interval_max;
adv_params.filter_policy = params->filter_policy;
adv_params.type = params->type;
+ adv_params.tx_power_level = params->tx_power_level;
if (ret)
g_variant_unref(ret);
if (enable == TRUE)
__bt_register_adv_slot_owner(sender, adv_handle, slot_id);
- else
- _bt_unregister_adv_slot_owner(slot_id);
le_adv_slot[slot_id].is_advertising = enable;
- BT_INFO_C("### Set advertising [%d]", enable);
+ BT_INFO_C("### Set advertising [%d], Slot id [%d]", enable, slot_id);
if (ret)
g_variant_unref(ret);
le_adv_slot[0].hold_timer_id = g_timeout_add(2000,
__bt_hold_current_advertising_timeout_cb, NULL);
} else {
- BT_ERR("It's NOT advertising");
+ BT_INFO("It's NOT advertising");
return BLUETOOTH_ERROR_NOT_IN_OPERATION;
}
return -1;
}
slot_check_list = g_malloc0(sizeof(gboolean) * le_feature_info.max_filter);
- if (slot_check_list == NULL) {
- BT_ERR("Fail to allocate memory");
- return -1;
- }
for (l = scanner_list; l != NULL; l = g_slist_next(l)) {
scanner = l->data;
g_array_free(arr_uuid, TRUE);
g_array_free(arr_uuid_mask, TRUE);
- g_array_free(arr_data, TRUE);
- g_array_free(arr_data_mask, TRUE);
}
if (filter->added_features & BLUETOOTH_LE_SCAN_FILTER_FEATURE_SERVICE_SOLICITATION_UUID) {
scanner = __bt_find_scanner_from_list(sender);
if (scanner == NULL) {
scanner = g_malloc0(sizeof(bt_adapter_le_scanner_t));
- if (scanner) {
- scanner->sender = strdup(sender);
- scanner_list = g_slist_append(scanner_list, scanner);
- }
+ scanner->sender = g_strdup(sender);
+ scanner_list = g_slist_append(scanner_list, scanner);
}
- filter_data = g_malloc0(sizeof(bluetooth_le_scan_filter_t));
- if (filter_data) {
+
+ if (scanner) {
+ filter_data = g_malloc0(sizeof(bluetooth_le_scan_filter_t));
memcpy(filter_data, filter, sizeof(bluetooth_le_scan_filter_t));
filter_data->slot_id = *slot_id;
- if (scanner)
- scanner->filter_list = g_slist_append(scanner->filter_list, filter_data);
+ scanner->filter_list = g_slist_append(scanner->filter_list, filter_data);
}
if (ret)
return BLUETOOTH_ERROR_NONE;
}
+static gboolean __start_le_scan_timeout(gpointer user_data)
+{
+ char *sender = (char *)user_data;
+ _bt_start_le_scan(sender);
+
+ return FALSE;
+}
+
+
int _bt_start_le_scan(const char *sender)
{
GDBusProxy *proxy;
if (scanner == NULL) {
scanner = g_malloc0(sizeof(bt_adapter_le_scanner_t));
- retv_if(scanner == NULL, BLUETOOTH_ERROR_INTERNAL);
-
- scanner->sender = strdup(sender);
+ scanner->sender = g_strdup(sender);
scanner_list = g_slist_append(scanner_list, scanner);
}
+ if (scanner->stop_pending == TRUE) {
+ BT_DBG("Waiting LEDiscoveryFinished");
+ g_timeout_add(500, (GSourceFunc)__start_le_scan_timeout, scanner->sender);
+ return BLUETOOTH_ERROR_NONE;
+ }
+
if (scanner->is_scanning == TRUE) {
BT_ERR("BT is already in LE scanning");
return BLUETOOTH_ERROR_IN_PROGRESS;
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
if (error) {
- BT_ERR("scan_filter_clear Fail: %s", error->message);
+ BT_ERR("scan_filter_enable Fail: %s", error->message);
g_clear_error(&error);
}
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
if (error) {
- BT_ERR("scan_filter_clear Fail: %s", error->message);
+ BT_ERR("scan_filter_enable Fail: %s", error->message);
g_clear_error(&error);
}
GDBusProxy *proxy;
GError *error = NULL;
GVariant *ret;
- bt_adapter_le_scanner_t *scanner = __bt_find_scanner_from_list(sender);
+ bt_adapter_le_scanner_t *scan_sender = __bt_find_scanner_from_list(sender);
+ bt_adapter_le_scanner_t *scanner;
GSList *l;
gboolean next_scanning = FALSE;
gboolean need_scan_filter = TRUE;
- if (scanner == NULL || scanner->is_scanning == FALSE)
+ if (scan_sender == NULL || scan_sender->is_scanning == FALSE)
return BLUETOOTH_ERROR_NOT_IN_OPERATION;
- scanner->is_scanning = FALSE;
+ scan_sender->is_scanning = FALSE;
+ scan_sender->stop_pending = TRUE;
for (l = scanner_list; l != NULL; l = g_slist_next(l)) {
scanner = l->data;
-1, NULL, &error);
if (error) {
- BT_ERR("scan_filter_clear Fail: %s", error->message);
+ BT_ERR("scan_filter_enable Fail: %s", error->message);
g_clear_error(&error);
}
BT_INFO("Enable LE Scan Filter");
scan_filter_enabled = TRUE;
}
+ BT_INFO("next_scanning exists. Keep the LE scanning");
+ scan_sender->stop_pending = FALSE;
return BLUETOOTH_ERROR_NONE;
} else {
if (scan_filter_enabled == TRUE) {
-1, NULL, &error);
if (error) {
- BT_ERR("scan_filter_clear Fail: %s", error->message);
+ BT_ERR("scan_filter_enable Fail: %s", error->message);
g_clear_error(&error);
}
for (l = scanner_list; l != NULL; l = g_slist_next(l)) {
scanner = l->data;
scanner->is_scanning = FALSE;
+ scanner->stop_pending = FALSE;
}
}
+static void __bt_free_le_scanner(void)
+{
+ GSList *l;
+ bt_adapter_le_scanner_t *scanner;
+
+ for (l = scanner_list; l != NULL; l = g_slist_next(l)) {
+ scanner = l->data;
+ g_free(scanner->sender);
+ g_slist_free_full(scanner->filter_list, g_free);
+ g_free(scanner);
+ }
+
+ g_slist_free(scanner_list);
+ scanner_list = NULL;
+
+ scan_filter_enabled = FALSE;
+ is_le_scanning = FALSE;
+ is_le_set_scan_parameter = FALSE;
+}
+
void _bt_set_le_scan_status(gboolean mode)
{
+ BT_DBG("set is_le_scanning : %d -> %d", is_le_scanning, mode);
is_le_scanning = mode;
}
}
}
+void _bt_send_ibeacon_scan_result_event(const bt_remote_ibeacon_dev_info_t *ibeacon_dev_info)
+{
+ int result = BLUETOOTH_ERROR_NONE;
+ GSList *l;
+ GVariant *param;
+ bt_adapter_le_scanner_t *scanner = NULL;
+
+ ret_if(ibeacon_dev_info == NULL);
+ BT_DBG("_bt_send_ibeacon_scan_result_event");
+
+ for (l = scanner_list; l != NULL; l = g_slist_next(l)) {
+ scanner = l->data;
+ if (scanner->is_scanning == FALSE)
+ continue;
+
+ param = g_variant_new("(isnnnsnnn)",
+ result,
+ ibeacon_dev_info->address,
+ ibeacon_dev_info->addr_type,
+ ibeacon_dev_info->company_id,
+ ibeacon_dev_info->ibeacon_type,
+ ibeacon_dev_info->uuid,
+ ibeacon_dev_info->major_id,
+ ibeacon_dev_info->minor_id,
+ ibeacon_dev_info->measured_power);
+
+ _bt_send_event(BT_LE_ADAPTER_EVENT, BLUETOOTH_EVENT_REMOTE_IBEACON_DEVICE_FOUND, param);
+ }
+}
+
int _bt_add_white_list(bluetooth_device_address_t *device_address, bluetooth_device_address_type_t address_type)
{
GDBusProxy *proxy;
reply = g_dbus_proxy_call_sync(proxy, "LEReadMaximumDataLength",
NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
- g_object_unref(proxy);
-
if (reply == NULL) {
BT_ERR("LEReadMaximumDataLength dBUS-RPC failed");
if (error != NULL) {
NULL,
&error);
- g_object_unref(proxy);
-
if (reply == NULL) {
BT_ERR("_bt_le_write_host_suggested_default_data_length dBUS-RPC failed");
if (error != NULL) {
return BLUETOOTH_ERROR_NONE;
}
+
+int _bt_service_adapter_le_init(void)
+{
+ le_adv_slot = g_malloc0(sizeof(bt_adapter_le_adv_slot_t) * le_feature_info.adv_inst_max);
+
+ return BLUETOOTH_ERROR_NONE;
+}
+
+void _bt_service_adapter_le_deinit(void)
+{
+ __bt_free_le_adv_slot();
+ __bt_free_le_scanner();
+}