Skip to content

Commit

Permalink
Bluetooth: Disable Latency Feature(DLF) implementation.
Browse files Browse the repository at this point in the history
bug: v/43848

Rootcause: DLF is an enhanced feature for optimizing latency performance, which is managed by Connection Manager. This submission is for the implementation of this feature.

Signed-off-by: chejinxian1 <[email protected]>
  • Loading branch information
chejinxian committed Dec 22, 2024
1 parent 2035ebc commit 3c11400
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ if(CONFIG_BLUETOOTH)
list(APPEND CSRCS ${BLUETOOTH_DIR}/service/src/l2cap_service.c)
endif()

if(CONFIG_LE_DLF_SUPPORT)
list(APPEND CSRCS ${BLUETOOTH_DIR}/service/src/connectino_manager_dlf.c)
endif()

file(GLOB APPEND_FILES ${BLUETOOTH_DIR}/service/stacks/*.c)
list(APPEND CSRCS ${APPEND_FILES})

Expand Down
9 changes: 9 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ config BLUETOOTH_GATTC_MAX_CONNECTIONS
int "GATT client max connections"
default 8

config BLUETOOTH_GATTS_MAX_CONNECTIONS
int "GATT sever max connections"
default 4

config BLUETOOTH_GATTS_MAX_ATTRIBUTE_NUM
int "GATT server max number of attributes contained in a table"
default 10
Expand Down Expand Up @@ -393,6 +397,11 @@ config BLUETOOTH_LE_ADVERTISER_MAX_NUM
config BLUETOOTH_LE_AUDIO_SUPPORT
bool "LE audio support"
default n

config LE_DLF_SUPPORT
bool "LE DLF support"
default n

endif #BLUETOOTH_BLE_SUPPORT
endif #BLUETOOTH_SERVICE

Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ endif #CONFIG_BLUETOOTH_BLE_SCAN
ifeq ($(CONFIG_BLUETOOTH_L2CAP), y)
CSRCS += service/src/l2cap_service.c
endif #CONFIG_BLUETOOTH_L2CAP
ifeq ($(CONFIG_LE_DLF_SUPPORT), y)
CSRCS += service/src/connection_manager_dlf.c
endif #CONFIG_LE_DLF_SUPPORT
CSRCS += service/stacks/*.c
ifneq ($(CONFIG_BLUETOOTH_STACK_BREDR_BLUELET)$(CONFIG_BLUETOOTH_STACK_LE_BLUELET),)
CSRCS += service/stacks/bluelet/*.c
Expand Down
4 changes: 4 additions & 0 deletions service/src/adapter_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "bt_uuid.h"
#include "btservice.h"
#include "callbacks_list.h"
#include "connection_manager.h"
#include "device.h"
#include "hci_error.h"
#include "sal_adapter_interface.h"
Expand Down Expand Up @@ -697,6 +698,9 @@ static void process_connection_state_changed_evt(bt_address_t* addr, acl_state_p
}
}

if (acl_params->connection_state == CONNECTION_STATE_DISCONNECTED)
bt_cm_process_disconnect_event(addr, acl_params->link_type);

/* send connection changed notification */
CALLBACK_FOREACH(CBLIST, adapter_callbacks_t, on_connection_state_changed, addr,
acl_params->link_type, acl_params->connection_state);
Expand Down
27 changes: 27 additions & 0 deletions service/src/connection_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include "connection_manager.h"
#include "bluetooth.h"

#ifdef CONFIG_LE_DLF_SUPPORT
#include "connection_manager_dlf.h"
#endif

typedef struct
{
bool inited;
Expand All @@ -42,12 +46,21 @@ void bt_cm_cleanup(void)
if (!manager->inited)
return;

#ifdef CONFIG_LE_DLF_SUPPORT
bt_cm_dlf_cleanup();
#endif

manager->inited = false;
}

bt_status_t bt_cm_enable_enhanced_mode(bt_address_t* addr, uint8_t mode)
{
switch (mode) {
case EM_LE_LOW_LATENCY: {
#ifdef CONFIG_LE_DLF_SUPPORT
return bt_cm_enable_dlf(addr);
#endif
}
default:
return BT_STATUS_NOT_SUPPORTED;
}
Expand All @@ -56,7 +69,21 @@ bt_status_t bt_cm_enable_enhanced_mode(bt_address_t* addr, uint8_t mode)
bt_status_t bt_cm_disable_enhanced_mode(bt_address_t* addr, uint8_t mode)
{
switch (mode) {
case EM_LE_LOW_LATENCY: {
#ifdef CONFIG_LE_DLF_SUPPORT
return bt_cm_disable_dlf(addr);
#endif
}
default:
return BT_STATUS_NOT_SUPPORTED;
}
}

void bt_cm_process_disconnect_event(bt_address_t* addr, uint8_t transport)
{
if (transport == BT_TRANSPORT_BLE) {
#ifdef CONFIG_LE_DLF_SUPPORT
bt_cm_disable_dlf(addr);
#endif
}
}
2 changes: 2 additions & 0 deletions service/src/connection_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ void bt_cm_cleanup(void);
bt_status_t bt_cm_enable_enhanced_mode(bt_address_t* peer_addr, uint8_t mode);
bt_status_t bt_cm_disable_enhanced_mode(bt_address_t* peer_addr, uint8_t mode);

void bt_cm_process_disconnect_event(bt_address_t* peer_addr, uint8_t transport);

#endif /*__BT_CONNECTION_MANAGER_H__*/
194 changes: 194 additions & 0 deletions service/src/connection_manager_dlf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/****************************************************************************
* Copyright (C) 2024 Xiaomi Corporation
*
* 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.
***************************************************************************/
#define LOG_TAG "cm_dlf"

#include "connection_manager_dlf.h"
#include "bt_debug.h"
#include "bt_utils.h"
#include "hci_parser.h"
#include "sal_adapter_interface.h"
#include "service_loop.h"
#include "vendor/bt_vendor.h"
#include "vendor/bt_vendor_common.h"

// TBD
// Finding an appropriate timer duration for DLF, even dynamically setting it.
// Current Connection Parameters Setting: Interaval 60ms & Latency 4 and Interval 15ms & Latency 3
#define BT_LE_DLF_TIMEOUT_SLOTS 1600 // 1600 * 0.625 ms = 1000 ms

#define MAX_DLF_LINK_NUM CONFIG_BLUETOOTH_GATTS_MAX_CONNECTIONS // Must be less than or equal to 16

typedef struct
{
bool is_enabled;
bt_address_t peer_addr;
hci_error_t status;
} cm_dlf_operation_t;

typedef struct
{
bt_address_t peer_addr;
uint16_t connection_handle;
uint16_t timeout_slots;
} cm_dlf_link_t;

typedef struct {
uint8_t dlf_link_num;
cm_dlf_link_t dlf_links[MAX_DLF_LINK_NUM];
} cm_dlf_t;

static cm_dlf_t g_cm_dlf;

static cm_dlf_link_t* bt_cm_find_dlf_link(const bt_address_t* peer_addr)
{
cm_dlf_t* manager = &g_cm_dlf;
cm_dlf_link_t* dlf_link;
uint8_t i;

for (i = 0; i < MAX_DLF_LINK_NUM; i++) {
dlf_link = &manager->dlf_links[i];

if (!bt_addr_compare(&dlf_link->peer_addr, peer_addr))
return dlf_link;
}

return NULL;
}

static void bt_cm_remove_dlf_link(cm_dlf_link_t* dlf_link)
{
cm_dlf_t* manager = &g_cm_dlf;

manager->dlf_link_num--;
memset(dlf_link, 0, sizeof(cm_dlf_link_t));
}

static void bt_cm_process_dlf_result(void* context)
{
cm_dlf_link_t* dlf_link;
cm_dlf_operation_t* dlf_operation = (cm_dlf_operation_t*)context;

BT_LOGI("DLF operation type: %d, command status: 0x%x", dlf_operation->is_enabled, dlf_operation->status);

if (dlf_operation->is_enabled && (dlf_operation->status == HCI_SUCCESS)) {
free(dlf_operation);
return;
}

dlf_link = bt_cm_find_dlf_link(&dlf_operation->peer_addr);
if (dlf_link)
bt_cm_remove_dlf_link(dlf_link);

free(dlf_operation);
}

static void bt_hci_event_callback(bt_hci_event_t* hci_event, void* context)
{
cm_dlf_operation_t* dlf_operation = (cm_dlf_operation_t*)context;

dlf_operation->status = hci_get_result(hci_event);
do_in_service_loop(bt_cm_process_dlf_result, dlf_operation);
}

static bool bt_cm_build_dlf_command(le_dlf_config_t* dlf_config, uint8_t* data, size_t* size, bool is_enabled)
{
if (is_enabled)
return le_dlf_enable_builder(dlf_config, data, size);

return le_dlf_disable_builder(dlf_config, data, size);
}

static bt_status_t bt_cm_send_dlf_command(cm_dlf_link_t* dlf_link, bool is_enabled)
{
uint8_t ogf;
uint16_t ocf;
uint8_t len;
uint8_t* payload;
uint8_t temp_data[CONFIG_DLF_COMMAND_MAX_LEN];
size_t size;
le_dlf_config_t dlf_config;
cm_dlf_operation_t* dlf_operation;

dlf_operation = (cm_dlf_operation_t*)malloc(sizeof(cm_dlf_operation_t));
if (!dlf_operation) {
BT_LOGE("malloc failed");
return BT_STATUS_FAIL;
}

dlf_operation->is_enabled = is_enabled;
dlf_operation->peer_addr = dlf_link->peer_addr;
dlf_config.connection_handle = dlf_link->connection_handle;
dlf_config.dlf_timeout = dlf_link->timeout_slots;

if (!bt_cm_build_dlf_command(&dlf_config, temp_data, &size, is_enabled)) {
BT_LOGD("build dlf command %d failed", is_enabled);
free(dlf_operation);
return BT_STATUS_NOT_SUPPORTED;
}

payload = temp_data;
len = size - sizeof(ogf) - sizeof(ocf);
STREAM_TO_UINT8(ogf, payload);
STREAM_TO_UINT16(ocf, payload);
return bt_sal_send_hci_command(ogf, ocf, len, payload, bt_hci_event_callback, dlf_operation);
}

void bt_cm_dlf_cleanup(void)
{
memset(&g_cm_dlf, 0, sizeof(g_cm_dlf));
}

bt_status_t bt_cm_enable_dlf(bt_address_t* peer_addr)
{
cm_dlf_t* manager = &g_cm_dlf;
uint16_t connection_handle;
cm_dlf_link_t* dlf_link;
bt_address_t empty_addr = { 0 };

if (manager->dlf_link_num >= MAX_DLF_LINK_NUM)
return BT_STATUS_NO_RESOURCES;

dlf_link = bt_cm_find_dlf_link(peer_addr);
if (dlf_link)
return BT_STATUS_FAIL;

dlf_link = bt_cm_find_dlf_link(&empty_addr);
if (!dlf_link) {
BT_LOGE("resource not found");
return BT_STATUS_FAIL;
}

connection_handle = bt_sal_get_acl_link_handle(peer_addr, BT_TRANSPORT_BLE);
if (connection_handle == BT_INVALID_CONNECTION_HANDLE)
return BT_STATUS_PARM_INVALID;

manager->dlf_link_num++;
dlf_link->peer_addr = *peer_addr;
dlf_link->connection_handle = connection_handle;
dlf_link->timeout_slots = BT_LE_DLF_TIMEOUT_SLOTS;
return bt_cm_send_dlf_command(dlf_link, true);
}

bt_status_t bt_cm_disable_dlf(bt_address_t* peer_addr)
{
cm_dlf_link_t* dlf_link;

dlf_link = bt_cm_find_dlf_link(peer_addr);
if (!dlf_link)
return BT_STATUS_SERVICE_NOT_FOUND;

return bt_cm_send_dlf_command(dlf_link, false);
}
28 changes: 28 additions & 0 deletions service/src/connection_manager_dlf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/****************************************************************************
* Copyright (C) 2024 Xiaomi Corporation
*
* 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 __CONNECTION_MANAGER_DLF_H__
#define __CONNECTION_MANAGER_DLF_H__

#include "bt_addr.h"
#include "bt_status.h"

void bt_cm_dlf_cleanup(void);

bt_status_t bt_cm_enable_dlf(bt_address_t* peer_addr);
bt_status_t bt_cm_disable_dlf(bt_address_t* peer_addr);

#endif /*__CONNECTION_MANAGER_DLF_H__*/

0 comments on commit 3c11400

Please sign in to comment.