From 3c114005c9625cf2e2a2e08f7ffee641956813dc Mon Sep 17 00:00:00 2001 From: chejinxian1 Date: Fri, 8 Nov 2024 22:20:20 +0800 Subject: [PATCH] Bluetooth: Disable Latency Feature(DLF) implementation. 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 --- CMakeLists.txt | 4 + Kconfig | 9 ++ Makefile | 3 + service/src/adapter_service.c | 4 + service/src/connection_manager.c | 27 ++++ service/src/connection_manager.h | 2 + service/src/connection_manager_dlf.c | 194 +++++++++++++++++++++++++++ service/src/connection_manager_dlf.h | 28 ++++ 8 files changed, 271 insertions(+) create mode 100644 service/src/connection_manager_dlf.c create mode 100644 service/src/connection_manager_dlf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a6a508b..2fb97c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/Kconfig b/Kconfig index 493725f..0e1a34f 100644 --- a/Kconfig +++ b/Kconfig @@ -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 @@ -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 diff --git a/Makefile b/Makefile index 9974db8..7eba697 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/service/src/adapter_service.c b/service/src/adapter_service.c index 0f3151c..a25aa0d 100644 --- a/service/src/adapter_service.c +++ b/service/src/adapter_service.c @@ -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" @@ -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); diff --git a/service/src/connection_manager.c b/service/src/connection_manager.c index 52d9b1e..14047e2 100644 --- a/service/src/connection_manager.c +++ b/service/src/connection_manager.c @@ -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; @@ -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; } @@ -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 + } } \ No newline at end of file diff --git a/service/src/connection_manager.h b/service/src/connection_manager.h index 49f7849..5c50c24 100644 --- a/service/src/connection_manager.h +++ b/service/src/connection_manager.h @@ -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__*/ \ No newline at end of file diff --git a/service/src/connection_manager_dlf.c b/service/src/connection_manager_dlf.c new file mode 100644 index 0000000..71fec4f --- /dev/null +++ b/service/src/connection_manager_dlf.c @@ -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); +} diff --git a/service/src/connection_manager_dlf.h b/service/src/connection_manager_dlf.h new file mode 100644 index 0000000..d91d030 --- /dev/null +++ b/service/src/connection_manager_dlf.h @@ -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__*/