From 121d22a9fcea7541e995874fddb56fa87d5ac4d2 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 01/16] PA sync: add event definitions. bug: v/82275 The event definition is necessary before the callbacks from periodic advertising sync. Signed-off-by: Zihao Gao --- service/src/pa_sync_event.h | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 service/src/pa_sync_event.h diff --git a/service/src/pa_sync_event.h b/service/src/pa_sync_event.h new file mode 100644 index 000000000..70b93908a --- /dev/null +++ b/service/src/pa_sync_event.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * Copyright (C) 2025 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 __PA_SYNC_EVENT_H__ +#define __PA_SYNC_EVENT_H__ + +#include "bluetooth.h" + +/** AoA Constant Tone Extension */ +#define BT_LE_PA_SYNC_EVENT_CTE_TYPE_AOA (0x00) +/** AoD Constant Tone Extension with 1 μs slots */ +#define BT_LE_PA_SYNC_EVENT_CTE_TYPE_AOD_1US (0x01) +/** AoD Constant Tone Extension with 2 μs slots */ +#define BT_LE_PA_SYNC_EVENT_CTE_TYPE_AOD_2US (0x02) +/** No Constant Tone Extension */ +#define BT_LE_PA_SYNC_EVENT_CTE_TYPE_NONE (0xFF) + +/** Data complete */ +#define BT_LE_PA_SYNC_EVENT_DATA_COMPLETE (0x00) +/** Data incomplete, more data to come */ +#define BT_LE_PA_SYNC_EVENT_DATA_MORE (0x01) +/** Data incomplete, data truncated, no more to come */ +#define BT_LE_PA_SYNC_EVENT_DATA_TRUNCATED (0x02) +/** Failed to receive an AUX_SYNC_SUBEVENT_IND PDU */ +#define BT_LE_PA_SYNC_EVENT_DATA_FAILED (0xFF) + +typedef enum { + SYNC_ESTABLISHED, + SYNC_TERMINATED, + SYNC_REPORT, +} pa_sync_event_type_t; + +typedef struct { + /** TxPower in dBm (-127 to +20). 0x7F if unavailable */ + int8_t tx_power; + + /** RSSI in dBm (-127 to +20). 0x7F if unavailable */ + int8_t rssi; + + /** CTE_Type, e.g., `BT_LE_PA_SYNC_EVENT_CTE_TYPE_NONE` */ + uint8_t cte; + + /** Periodic_Event_Counter */ + uint16_t cnt; + + /** The subevent number, range from 0x00 to 0x7F. 0xFF if no subevents */ + uint8_t subevent; + + /** Data_Status, e.g., `BT_LE_PA_SYNC_EVENT_DATA_COMPLETE` */ + uint8_t status; + + /** Data_Length */ + uint8_t adv_data_len; + + /** Data received from a Periodic Advertising packet */ + uint8_t adv_data[0]; +} pa_sync_event_report_data_t; + +typedef struct { + pa_sync_event_type_t event; + bt_controller_id_t id; + bt_le_address_t addr; + uint8_t data[0]; /**< Event specific data, e.g., @ref pa_sync_event_report_data_t */ +} pa_sync_event_t; + +#endif /* __PA_SYNC_EVENT_H__ */ \ No newline at end of file From 809afcf7de9a8a01c84cd134a0995997ed8c2fa1 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 02/16] SAL: add definitions for PA sync API. bug: v/82275 This patch defines the APIs required to synchronize a periodic advertising train. Signed-off-by: Zihao Gao --- .../stacks/include/sal_pa_sync_interface.h | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 service/stacks/include/sal_pa_sync_interface.h diff --git a/service/stacks/include/sal_pa_sync_interface.h b/service/stacks/include/sal_pa_sync_interface.h new file mode 100644 index 000000000..8e6e06643 --- /dev/null +++ b/service/stacks/include/sal_pa_sync_interface.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * Copyright (C) 2025 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 __SAL_PA_SYNC_INTERFACE_H__ +#define __SAL_PA_SYNC_INTERFACE_H__ + +#include "bluetooth.h" + +#ifndef SAL_BIT +#define SAL_BIT(x) (1UL << (x)) +#endif + +/** Bit 0 in Options: + * - 0: Use the Advertising_SID, Advertiser_Address_Type, and Advertiser_Address parameters to + * determine which advertiser to listen to + * - 1: Use the Periodic Advertiser List to determine which advertiser to listen to + * See @ref bt_sal_pa_list_add */ +#define BT_SAL_PA_SYNC_OPTION_USE_LIST SAL_BIT(0) + +/** Bit 1 in Options: + * - 0: Reporting initially enabled + * - 1: Reporting initially disabled */ +#define BT_SAL_PA_SYNC_OPTION_REPORTING_DISABLED SAL_BIT(1) + +/** Bit 2 in Options: + * - 0: Duplicate filtering initially disabled + * - 1: Duplicate filtering initially enabled */ +#define BT_SAL_PA_SYNC_OPTION_FILTER_ENABLED SAL_BIT(2) + +/** Bit 0 in Sync_CTE_Type: + * - 1: Do not sync to packets with an AoA Constant Tone Extension */ +#define BT_SAL_PA_SYNC_CTE_TYPE_NO_AOA SAL_BIT(0) + +/** Bit 1 in Sync_CTE_Type: + * - 1: Do not sync to packets with an AoD Constant Tone Extension with 1 μs slots */ +#define BT_SAL_PA_SYNC_CTE_TYPE_NO_AOD_1US SAL_BIT(1) + +/** Bit 2 in Sync_CTE_Type: + * - 1: Do not sync to packets with an AoD Constant Tone Extension with 2 μs slots */ +#define BT_SAL_PA_SYNC_CTE_TYPE_NO_AOD_2US SAL_BIT(2) + +/** Bit 3 in Sync_CTE_Type: (RFU) + * - 1: Do not sync to packets with a type 3 Constant Tone Extension */ +#define BT_SAL_PA_SYNC_CTE_TYPE_NO_AOD_TYPE3 SAL_BIT(3) + +/** Bit 4 in Sync_CTE_Type: + * - 1: Do not sync to packets without a Constant Tone Extension */ +#define BT_SAL_PA_SYNC_CTE_TYPE_CTE_ONLY SAL_BIT(4) + +typedef struct bt_sal_pa_sync_param { + /** Options, e.g., BT_SAL_PA_SYNC_OPTION_USE_LIST */ + uint8_t ops; + + /** `Advertising_SID`, refers to the Advertising SID subfield in the `ADI` field used to + * identify the Periodic Advertising. Range from 0x00 to 0x0F. Only valid when + * `BT_SAL_PA_SYNC_OPTION_USE_LIST` is not set in `ops`, otherwise ignored */ + uint8_t sid; + + /** `Advertiser_Address` and `Advertiser_Address_Type` of the remote device. Only valid when + * `BT_SAL_PA_SYNC_OPTION_USE_LIST` is not set in `ops`, otherwise ignored */ + bt_le_address_t addr; + + /** The maximum number of periodic advertising events that can be skipped after a successful + * reception. Range from 0x0000 to 0x01F3 */ + uint16_t skip; + + /** Synchronization timeout for the periodic advertising train, measured in 10 milliseconds. + * Range from 0x000A to 0x4000 */ + uint16_t timeout; + + /** Sync_CTE_Type, e.g., BT_SAL_PA_SYNC_CTE_TYPE_NO_AOA */ + uint8_t cte; +} bt_sal_pa_sync_param_t; + +bt_status_t bt_sal_pa_create_sync(bt_controller_id_t id, const bt_sal_pa_sync_param_t* params); +bt_status_t bt_sal_pa_terminate_sync(bt_controller_id_t id, uint8_t sid, + const bt_le_address_t* addr); +bt_status_t bt_sal_pa_list_add(bt_controller_id_t id, uint8_t sid, const bt_le_address_t* addr); +bt_status_t bt_sal_pa_list_remove(bt_controller_id_t id, uint8_t sid, const bt_le_address_t* addr); +bt_status_t bt_sal_pa_list_clear(bt_controller_id_t id); + +#endif /* __SAL_PA_SYNC_INTERFACE_H__ */ \ No newline at end of file From 6b70a808027b175dc15d8be9ef9b58291b6b34ad Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 03/16] SAL: add descriptions for PA sync APIs. bug: v/82275 This patch includes the documentation of SAL APIs. Signed-off-by: Zihao Gao --- .../stacks/include/sal_pa_sync_interface.h | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/service/stacks/include/sal_pa_sync_interface.h b/service/stacks/include/sal_pa_sync_interface.h index 8e6e06643..2acb261b5 100644 --- a/service/stacks/include/sal_pa_sync_interface.h +++ b/service/stacks/include/sal_pa_sync_interface.h @@ -85,11 +85,72 @@ typedef struct bt_sal_pa_sync_param { uint8_t cte; } bt_sal_pa_sync_param_t; +/** + * @brief LE Periodic Advertising Create Sync command. + * + * This command is used to synchronize with a single periodic advertising train from an advertiser + * and begin receiving periodic advertising packets. + * + * @param[in] id The Controller ID. + * @param[in] params The parameters used to synchronize the periodic advertising train. + * + * @note A @ref SYNC_ESTABLISHED event, associated with a `handle`, shall be generated when starting + * to receive periodic advertising packets. + * @note A @ref SYNC_TERMINATED event shall be generated if the sync fails to establish. + * @note A @ref SYNC_REPORT event may be generated when a periodic advertising packet is received. + */ bt_status_t bt_sal_pa_create_sync(bt_controller_id_t id, const bt_sal_pa_sync_param_t* params); + +/** + * @brief LE Periodic Advertising Terminate Sync command. + * + * This command is used to stop reception of the periodic advertising train identified by the + * `handle`. + * + * @param[in] id The Controller ID. + * @param[in] sid The Advertising SID. + * @param[in] addr Public device address, random device address, public identity address, or random + * (static) identity address of the advertiser. + * + * @note A @ref SYNC_TERMINATED event shall be generated when this command is completed. + */ bt_status_t bt_sal_pa_terminate_sync(bt_controller_id_t id, uint8_t sid, const bt_le_address_t* addr); + +/** + * @brief LE Add Device To Periodic Advertiser List command. + * + * This command is used to add an entry, consisting of a single device address and SID, to the + * Periodic Advertiser list stored in the Controller. + * + * @param[in] id The Controller ID. + * @param[in] sid The Advertising SID. + * @param[in] addr Public device address, random device address, public identity address, or random + * (static) identity address of the advertiser. + */ bt_status_t bt_sal_pa_list_add(bt_controller_id_t id, uint8_t sid, const bt_le_address_t* addr); + +/** + * @brief LE Remove Device From Periodic Advertiser List command. + * + * This command is used to remove one entry from the list of Periodic Advertisers stored in the + * Controller. + * + * @param[in] id The Controller ID. + * @param[in] sid The Advertising SID. + * @param[in] addr Public device address, random device address, public identity address, or random + * (static) identity address of the advertiser. + */ bt_status_t bt_sal_pa_list_remove(bt_controller_id_t id, uint8_t sid, const bt_le_address_t* addr); + +/** + * @brief LE Clear Periodic Advertiser List command. + * + * This command is used to remove all entries from the list of periodic advertisers in the + * Controller. + * + * @param[in] id The Controller ID. + */ bt_status_t bt_sal_pa_list_clear(bt_controller_id_t id); #endif /* __SAL_PA_SYNC_INTERFACE_H__ */ \ No newline at end of file From 4a30d6856d2c6de2a996c102d3db773d870131dc Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 04/16] PA sync: add empty service bug: v/82379 A initial version that has nothing implemented. Signed-off-by: Zihao Gao --- service/src/pa_sync_service.c | 40 +++++++++++++++++++ service/src/pa_sync_service.h | 27 +++++++++++++ service/stacks/zephyr/sal_pa_sync_interface.c | 15 +++++++ 3 files changed, 82 insertions(+) create mode 100644 service/src/pa_sync_service.c create mode 100644 service/src/pa_sync_service.h create mode 100644 service/stacks/zephyr/sal_pa_sync_interface.c diff --git a/service/src/pa_sync_service.c b/service/src/pa_sync_service.c new file mode 100644 index 000000000..551f7f924 --- /dev/null +++ b/service/src/pa_sync_service.c @@ -0,0 +1,40 @@ +/**************************************************************************** + * Copyright (C) 2025 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 "pa_sync" + +#include "pa_sync_service.h" + +#include "utils/log.h" + +bt_status_t pa_sync_init(void) +{ + BT_LOGD("%s", __func__); +} + +bt_status_t pa_sync_cleanup(void) +{ + BT_LOGD("%s", __func__); +} + +bt_status_t pa_sync_search_create(void) +{ + BT_LOGD("%s", __func__); +} + +bt_status_t pa_sync_search_terminate(void) +{ + BT_LOGD("%s", __func__); +} diff --git a/service/src/pa_sync_service.h b/service/src/pa_sync_service.h new file mode 100644 index 000000000..8909bfba0 --- /dev/null +++ b/service/src/pa_sync_service.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * Copyright (C) 2025 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 __PA_SYNC_SERVICE_H__ +#define __PA_SYNC_SERVICE_H__ + +#include "bt_status.h" + +bt_status_t pa_sync_init(void); +bt_status_t pa_sync_cleanup(void); +bt_status_t pa_sync_create(void); +bt_status_t pa_sync_terminate(void); + +#endif /* __PA_SYNC_SERVICE_H__ */ \ No newline at end of file diff --git a/service/stacks/zephyr/sal_pa_sync_interface.c b/service/stacks/zephyr/sal_pa_sync_interface.c new file mode 100644 index 000000000..253839592 --- /dev/null +++ b/service/stacks/zephyr/sal_pa_sync_interface.c @@ -0,0 +1,15 @@ +/**************************************************************************** + * Copyright (C) 2025 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. + ***************************************************************************/ \ No newline at end of file From c95da27bd3605304bc1b58eb64a051943fba2ac2 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 05/16] PA sync: add Kconfig bug: v/82379 A initial version that starts compiling the files. Signed-off-by: Zihao Gao --- CMakeLists.txt | 8 ++++++++ Kconfig | 14 ++++++++++---- Makefile | 6 ++++++ service/src/adapter_service.c | 10 ++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e76d30bdd..d5c99e835 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,6 +252,10 @@ if(CONFIG_BLUETOOTH) ${BLUETOOTH_DIR}/service/src/scan_filter.c) endif() + if(CONFIG_BLUETOOTH_PA_SYNC) + list(APPEND CSRCS ${BLUETOOTH_DIR}/service/src/pa_sync_service.c) + endif() + if(CONFIG_BLUETOOTH_L2CAP) list(APPEND CSRCS ${BLUETOOTH_DIR}/service/src/l2cap_service.c) endif() @@ -318,6 +322,10 @@ if(CONFIG_BLUETOOTH) list(APPEND CSRCS ${BLUETOOTH_DIR}/service/stacks/zephyr/sal_le_scan_interface.c) endif() + if(CONFIG_BLUETOOTH_PA_SYNC) + list(APPEND CSRCS ${BLUETOOTH_DIR}/service/stacks/zephyr/sal_pa_sync_interface.c) + endif() + if(CONFIG_BLUETOOTH_GATT_CLIENT) list(APPEND CSRCS ${BLUETOOTH_DIR}/service/stacks/zephyr/sal_gatt_client_interface.c) endif() diff --git a/Kconfig b/Kconfig index abe3e1062..045416f99 100644 --- a/Kconfig +++ b/Kconfig @@ -104,10 +104,16 @@ config BLUETOOTH_BLE_SCAN_FILTER depends on BLUETOOTH_BLE_SCAN config BLUETOOTH_HCI_FILTER - bool "Enable Bluetooth HCI filter" - default y - help - Enable Bluetooth HCI filter + bool "Enable Bluetooth HCI filter" + default y + help + Enable Bluetooth HCI filter + +config BLUETOOTH_PA_SYNC + bool "LE Periodic Advertising sync support" + default n + depends on BLUETOOTH_BLE_SUPPORT + depends on BLUETOOTH_BLE_SCAN config BLUETOOTH_L2CAP bool "L2CAP dynamic channel support" diff --git a/Makefile b/Makefile index dfc14bfed..84047b3df 100644 --- a/Makefile +++ b/Makefile @@ -212,6 +212,9 @@ ifeq ($(CONFIG_BLUETOOTH_BLE_SCAN), y) CSRCS += service/src/scan_record.c CSRCS += service/src/scan_filter.c endif #CONFIG_BLUETOOTH_BLE_SCAN +ifeq ($(CONFIG_BLUETOOTH_PA_SYNC), y) + CSRCS += service/src/pa_sync_service.c +endif #CONFIG_BLUETOOTH_PA_SYNC ifeq ($(CONFIG_BLUETOOTH_L2CAP), y) CSRCS += service/src/l2cap_service.c endif #CONFIG_BLUETOOTH_L2CAP @@ -259,6 +262,9 @@ endif #CONFIG_BLUETOOTH_BLE_ADV ifeq ($(CONFIG_BLUETOOTH_BLE_SCAN), y) CSRCS += service/stacks/zephyr/sal_le_scan_interface.c endif #CONFIG_BLUETOOTH_BLE_SCAN +ifeq ($(CONFIG_BLUETOOTH_PA_SYNC), y) + CSRCS += service/stacks/zephyr/sal_pa_sync_interface.c +endif #CONFIG_BLUETOOTH_PA_SYNC ifeq ($(CONFIG_BLUETOOTH_GATT_CLIENT), y) CSRCS += service/stacks/zephyr/sal_gatt_client_interface.c endif #CONFIG_BLUETOOTH_GATT_CLIENT diff --git a/service/src/adapter_service.c b/service/src/adapter_service.c index b248daa72..bf22492b8 100644 --- a/service/src/adapter_service.c +++ b/service/src/adapter_service.c @@ -33,6 +33,9 @@ #ifdef CONFIG_BLUETOOTH_L2CAP #include "l2cap_service.h" #endif +#ifdef CONFIG_BLUETOOTH_PA_SYNC +#include "pa_sync_service.h" +#endif #include "advertising.h" #include "bluetooth.h" #include "bluetooth_define.h" @@ -1441,6 +1444,10 @@ void adapter_on_le_enabled(bool enablebt) /* enable scan manager */ #ifdef CONFIG_BLUETOOTH_BLE_SCAN scan_manager_init(); +#endif + /* enable periodic advertising sync service */ +#ifdef CONFIG_BLUETOOTH_PA_SYNC + pa_sync_init(); #endif /* enable L2CAP service */ #ifdef CONFIG_BLUETOOTH_L2CAP @@ -1460,6 +1467,9 @@ void adapter_on_le_disabled(void) #ifdef CONFIG_BLUETOOTH_BLE_ADV adv_manager_cleanup(); #endif +#ifdef CONFIG_BLUETOOTH_PA_SYNC + pa_sync_cleanup(); +#endif #ifdef CONFIG_BLUETOOTH_BLE_SCAN adapter_lock(); bt_list_clear(g_adapter_service.le_devices); From f41d3bb5c8f6f65483e9e1d629acdec64654a7c1 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 06/16] PA sync: init and uninit for PA sync. bug: v/82379 Init and uninit for PA sync. Signed-off-by: Zihao Gao --- service/src/pa_sync_service.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/service/src/pa_sync_service.c b/service/src/pa_sync_service.c index 551f7f924..2abac63c3 100644 --- a/service/src/pa_sync_service.c +++ b/service/src/pa_sync_service.c @@ -17,24 +17,51 @@ #include "pa_sync_service.h" +#include "bluetooth.h" + #include "utils/log.h" +typedef struct pa_sync_info { + int nothing_but_wait_for_the_first_variable; +} pa_sync_info_t; + +static pa_sync_info_t* g_pa_sync_info = NULL; + bt_status_t pa_sync_init(void) { BT_LOGD("%s", __func__); + + if (g_pa_sync_info) + return BT_STATUS_BUSY; + + g_pa_sync_info = zalloc(sizeof(pa_sync_info_t)); + + return BT_STATUS_SUCCESS; } bt_status_t pa_sync_cleanup(void) { BT_LOGD("%s", __func__); + + if (!g_pa_sync_info) + return BT_STATUS_DONE; + + free(g_pa_sync_info); + g_pa_sync_info = NULL; + + return BT_STATUS_SUCCESS; } -bt_status_t pa_sync_search_create(void) +bt_status_t pa_sync_create(void) { BT_LOGD("%s", __func__); + + return BT_STATUS_UNSUPPORTED; } -bt_status_t pa_sync_search_terminate(void) +bt_status_t pa_sync_terminate(void) { BT_LOGD("%s", __func__); + + return BT_STATUS_UNSUPPORTED; } From 9124539f70c7b9fbce9043f536bb2474f58fabe9 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 07/16] PA sync: API for parsing advertising report bug: v/82379 Periodic advertising often comes from extended scanning, so we add an parser here. An alternative is Periodic Advertising Sync Transfer (to be implemented later). Signed-off-by: Zihao Gao --- framework/include/bluetooth.h | 5 +++ framework/include/bt_pa_sync.h | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 framework/include/bt_pa_sync.h diff --git a/framework/include/bluetooth.h b/framework/include/bluetooth.h index 9ce8e5be2..df9124b02 100644 --- a/framework/include/bluetooth.h +++ b/framework/include/bluetooth.h @@ -349,6 +349,11 @@ typedef uint8_t bt_128key_t[16]; #define BT_UUID_MAX_NUM (32) #define BT_UUID_128_LEN (16) +/* `Broadcast_ID` is 24-bit (0x000000-0xFFFFFF). Other values are invalid. */ +#define BT_INVALID_BROADCAST_ID (0xFFFFFFFF) + +#define BT_BROADCAST_NAME_MAX_LEN (128) + typedef struct { bt_address_t addr; int8_t rssi; diff --git a/framework/include/bt_pa_sync.h b/framework/include/bt_pa_sync.h new file mode 100644 index 000000000..40cd29c1e --- /dev/null +++ b/framework/include/bt_pa_sync.h @@ -0,0 +1,63 @@ +/**************************************************************************** + * Copyright (C) 2025 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 __BT_PA_SYNC_H__ +#define __BT_PA_SYNC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bt_le_scan.h" + +#ifndef BTSYMBOLS +#define BTSYMBOLS(s) s +#endif + +/** + * @brief Information about the periodic advertising sync. + */ +typedef struct bt_pa_sync_info { + /** Advertising Set ID (SID) subfield of the `AdvDataInfo` (ADI) */ + uint8_t sid; + + /** TxPower in dBm (-127 to +20). 0x7F if unavailable */ + int8_t tx_power; + + /** Present if available: Broadcast_ID from Broadcast Audio Announcement. + * Otherwise, `BT_INVALID_BROADCAST_ID` */ + uint32_t broadcast_id; + + /** UTF-8 string of the `Broadcast_Name` field in `AdvData` (if present) */ + char broadcast_name[BT_BROADCAST_NAME_MAX_LEN + 1]; +} bt_pa_sync_info_t; + +/** + * @brief Parse an advertising report and check if periodic advertising is present. + * + * @param[out] info Buffer to store the parsed periodic advertising info + * @param[in] result Advertising report from the scan result callback + * + * @return `BT_STATUS_SUCCESS` if periodic advertising is found + * @return `BT_STATUS_NOT_FOUND` if no periodic advertising is found + * @return Other negative `bt_status_t` error codes on failure. + */ +bt_status_t bt_pa_sync_parse_adv_data(bt_pa_sync_info_t* info, const ble_scan_result_t* result); + +#ifdef __cplusplus +} +#endif + +#endif From ffd1d716e1093b5c8e788778e599cf832f16a1a6 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 08/16] Auracast sink: Add bttool for Auracast sink bug: v/82380 Initial version of Auracast sink test tool Signed-off-by: Zihao Gao --- CMakeLists.txt | 4 +++ Kconfig | 5 ++++ Makefile | 4 +++ tools/auracast_sink.c | 65 +++++++++++++++++++++++++++++++++++++++++++ tools/bt_tools.c | 9 ++++++ tools/bt_tools.h | 4 +++ 6 files changed, 91 insertions(+) create mode 100644 tools/auracast_sink.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d5c99e835..6626867d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -651,6 +651,10 @@ if(CONFIG_BLUETOOTH) list(APPEND CSRCS ${BLUETOOTH_DIR}/tools/lea_tbs.c) endif() + if(CONFIG_BLUETOOTH_AURACAST_SINK) + list(APPEND CSRCS ${BLUETOOTH_DIR}/tools/auracast_sink.c) + endif() + if(CONFIG_BLUETOOTH_STORAGE_UPDATE) list(APPEND CSRCS ${BLUETOOTH_DIR}/tools/storage_update/storage_tool.c) endif() diff --git a/Kconfig b/Kconfig index 045416f99..b3f0d3c8f 100644 --- a/Kconfig +++ b/Kconfig @@ -620,6 +620,11 @@ config BLUETOOTH_LEAUDIO_SERVER_CSIS_RANK endif # BLUETOOTH_LEAUDIO_SERVER +config BLUETOOTH_AURACAST_SINK + bool "Auracast Sink role" + default n + depends on BLUETOOTH_PA_SYNC + endmenu #Bluetooth LE Audio menu "Bluetooth Audio Transport" diff --git a/Makefile b/Makefile index 84047b3df..3b2009f92 100644 --- a/Makefile +++ b/Makefile @@ -510,6 +510,10 @@ ifeq ($(CONFIG_BLUETOOTH_LEAUDIO_TBS), y) CSRCS += tools/lea_tbs.c endif +ifeq ($(CONFIG_BLUETOOTH_AURACAST_SINK), y) + CSRCS += tools/auracast_sink.c +endif + ifeq ($(CONFIG_BLUETOOTH_STORAGE_UPDATE), y) CSRCS += tools/storage_update/storage_tool.c endif #CONFIG_BLUETOOTH_STORAGE_UPDATE diff --git a/tools/auracast_sink.c b/tools/auracast_sink.c new file mode 100644 index 000000000..4c1f91466 --- /dev/null +++ b/tools/auracast_sink.c @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright (C) 2025 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. + ***************************************************************************/ +#include "bt_tools.h" + +typedef struct { + bt_scanner_t* scanner; +} bttool_auracast_sink_t; + +static int scan_cmd(void* handle, int argc, char* argv[]); + +static bttool_auracast_sink_t* g_auracast_sink = NULL; +static bt_command_t g_auracast_sink_tables[] = { + { "scan", scan_cmd, 0, "\"Search for nearby Auracast sources\"" }, +}; + +static void usage(void) +{ + printf("Usage:\n"); + printf("\taddress: peer device address like 00:01:02:03:04:05\n"); + printf("Commands:\n"); + for (int i = 0; i < ARRAY_SIZE(g_auracast_sink_tables); i++) { + printf("\t%-8s\t%s\n", g_auracast_sink_tables[i].cmd, g_auracast_sink_tables[i].help); + } +} + +int scan_cmd(void* handle, int argc, char* argv[]) +{ + return CMD_OK; +} + +int auracast_sink_command_init(void* handle) +{ + return CMD_OK; +} + +void auracast_sink_command_uninit(void* handle) +{ +} + +int auracast_sink_command_exec(void* handle, int argc, char* argv[]) +{ + int ret = CMD_USAGE_FAULT; + + if (argc > 0) + ret = execute_command_in_table_offset(handle, g_auracast_sink_tables, + ARRAY_SIZE(g_auracast_sink_tables), argc, argv, 0); + + if (ret < 0) + usage(); + + return ret; +} diff --git a/tools/bt_tools.c b/tools/bt_tools.c index d720f74a3..ac9bc5baa 100644 --- a/tools/bt_tools.c +++ b/tools/bt_tools.c @@ -232,6 +232,9 @@ static bt_command_t g_cmd_tables[] = { #ifdef CONFIG_BLUETOOTH_LEAUDIO_VMICP { "vmicp", vmicp_command_exec, 0, "vcp/micp client cmd, input \'vmicp\' show usage" }, #endif +#ifdef CONFIG_BLUETOOTH_AURACAST_SINK + { "aurasnk", auracast_sink_command_exec, 0, "auracast sink cmd, input \'aurasnk\' show usage" }, +#endif #ifdef CONFIG_BLUETOOTH_STORAGE_UPDATE { "storage", storage_command_exec, 0, "storage update cmd, input \'storage\' show usage" }, #endif @@ -358,6 +361,9 @@ static void bt_tool_init(void* handle) #ifdef CONFIG_BLUETOOTH_LEAUDIO_VMICP lea_vmicp_command_init(handle); #endif +#ifdef CONFIG_BLUETOOTH_AURACAST_SINK + auracast_sink_command_init(handle); +#endif #ifdef CONFIG_BLUETOOTH_STORAGE_UPDATE storage_command_init(handle); #endif @@ -426,6 +432,9 @@ static void bt_tool_uninit(void* handle) #ifdef CONFIG_BLUETOOTH_LEAUDIO_VMICP lea_vmicp_command_uninit(handle); #endif +#ifdef CONFIG_BLUETOOTH_AURACAST_SINK + auracast_sink_command_uninit(handle); +#endif #ifdef CONFIG_BLUETOOTH_STORAGE_UPDATE storage_command_uninit(handle); #endif diff --git a/tools/bt_tools.h b/tools/bt_tools.h index e28fc350f..d5224fa28 100644 --- a/tools/bt_tools.h +++ b/tools/bt_tools.h @@ -190,6 +190,10 @@ int lea_vmicp_command_init(void* handle); void lea_vmicp_command_uninit(void* handle); int vmicp_command_exec(void* handle, int argc, char* argv[]); +int auracast_sink_command_init(void* handle); +void auracast_sink_command_uninit(void* handle); +int auracast_sink_command_exec(void* handle, int argc, char* argv[]); + int storage_command_init(void* handle); void storage_command_uninit(void* handle); int storage_command_exec(void* handle, int argc, char* argv[]); From 43dce33d104e879710ff59ff6afbc48403ade641 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 09/16] Auracast sink: allow to start extended scan bug: v/82380 Add scan command to search active Auracast sources. Signed-off-by: Zihao Gao --- tools/auracast_sink.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tools/auracast_sink.c b/tools/auracast_sink.c index 4c1f91466..88aff2a32 100644 --- a/tools/auracast_sink.c +++ b/tools/auracast_sink.c @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ + +#include "bt_le_scan.h" +#include "bt_pa_sync.h" #include "bt_tools.h" typedef struct { @@ -36,18 +39,88 @@ static void usage(void) } } +static void on_scan_result(bt_scanner_t* scanner, ble_scan_result_t* result) +{ + bt_status_t status; + bt_pa_sync_info_t* info; + + if (g_auracast_sink->scanner != scanner) + return; + + info = malloc(sizeof(bt_pa_sync_info_t)); + if (info == NULL) + return; + + status = bt_pa_sync_parse_adv_data(info, result); + if (status != BT_STATUS_SUCCESS) + return; +} + +static void on_scan_status(bt_scanner_t* scanner, uint8_t status) +{ + PRINT("%s, status = %d", __func__, status); + if (g_auracast_sink->scanner != scanner) + return; + + if (status != BT_STATUS_SUCCESS) + g_auracast_sink->scanner = NULL; +} + +static void on_scan_stopped(bt_scanner_t* scanner) +{ + PRINT("%s", __func__); + if (g_auracast_sink->scanner != scanner) + return; + + g_auracast_sink->scanner = NULL; +} + +static const scanner_callbacks_t scanner_cbs = { + .size = sizeof(scanner_cbs), + .on_scan_result = on_scan_result, + .on_scan_start_status = on_scan_status, + .on_scan_stopped = on_scan_stopped, +}; + +static const ble_scan_settings_t default_scan_settings = { + .scan_mode = BT_SCAN_MODE_LOW_LATENCY, + .legacy = false, + .scan_type = BT_LE_SCAN_TYPE_PASSIVE, + .scan_phy = BT_LE_1M_PHY, + .policy.policy = 0, /**< Unfiltered */ +}; + int scan_cmd(void* handle, int argc, char* argv[]) { + ble_scan_settings_t settings; + + if (g_auracast_sink->scanner) { + PRINT("Already scanning"); + return CMD_USAGE_FAULT; + } + + memcpy(&settings, &default_scan_settings, sizeof(settings)); + + g_auracast_sink->scanner = bt_le_start_scan_settings(handle, &settings, &scanner_cbs); + if (g_auracast_sink->scanner == NULL) + return CMD_ERROR; + return CMD_OK; } int auracast_sink_command_init(void* handle) { + g_auracast_sink = zalloc(sizeof(bttool_auracast_sink_t)); + if (!g_auracast_sink) + return CMD_ERROR; + return CMD_OK; } void auracast_sink_command_uninit(void* handle) { + free(g_auracast_sink); + g_auracast_sink = NULL; } int auracast_sink_command_exec(void* handle, int argc, char* argv[]) From 5f7f7595faa64e5264ae757c6219a33e7dc3effb Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 10/16] PA sync: allow to parse scan result bug: v/82379 Parse the scan result at the client side, so we can reduce the uplink data. Signed-off-by: Zihao Gao --- CMakeLists.txt | 4 +++ Makefile | 4 +++ framework/common/advertiser_data_helper.c | 43 +++++++++++++++++++++++ framework/include/advertiser_data.h | 23 ++++++++++++ framework/socket/bt_pa_sync.c | 17 +++++++++ 5 files changed, 91 insertions(+) create mode 100644 framework/socket/bt_pa_sync.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6626867d2..27746516a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,6 +180,10 @@ if(CONFIG_BLUETOOTH) list(APPEND CSRCS ${BLUETOOTH_DIR}/service/ipc/socket/src/bt_socket_le_scan.c) endif() + if(CONFIG_BLUETOOTH_PA_SYNC) + list(APPEND CSRCS ${BLUETOOTH_DIR}/framework/socket/bt_pa_sync.c) + endif() + if(CONFIG_BLUETOOTH_PAN) list(APPEND CSRCS ${BLUETOOTH_DIR}/framework/socket/bt_pan.c) list(APPEND CSRCS ${BLUETOOTH_DIR}/service/ipc/socket/src/bt_socket_pan.c) diff --git a/Makefile b/Makefile index 3b2009f92..49a302cbb 100644 --- a/Makefile +++ b/Makefile @@ -150,6 +150,10 @@ CSRCS += framework/socket/bt_le_scan.c CSRCS += service/ipc/socket/src/bt_socket_scan.c endif #CONFIG_BLUETOOTH_BLE_SCAN +ifeq ($(CONFIG_BLUETOOTH_PA_SYNC), y) +CSRCS += framework/socket/bt_pa_sync.c +endif #CONFIG_BLUETOOTH_PA_SYNC + ifeq ($(CONFIG_BLUETOOTH_PAN), y) CSRCS += framework/socket/bt_pan.c CSRCS += service/ipc/socket/src/bt_socket_pan.c diff --git a/framework/common/advertiser_data_helper.c b/framework/common/advertiser_data_helper.c index 35f8b804d..17598008c 100644 --- a/framework/common/advertiser_data_helper.c +++ b/framework/common/advertiser_data_helper.c @@ -17,6 +17,7 @@ #include #include "advertiser_data.h" +#include "bt_pa_sync.h" #include "bt_debug.h" typedef struct { @@ -213,3 +214,45 @@ bool advertiser_data_dump(uint8_t* data, uint16_t len, ad_dump_cb_t dump) return true; } + +bool advertiser_data_parse(const uint8_t* data, uint8_t len, ad_parse_cb_t cb, void* context) +{ + adv_data_t* ad; + uint16_t offset = 0; + + if (!cb) + return false; + + while (offset < len) { + ad = (adv_data_t*)&data[offset]; + if (ad->len == 0) { /**< AD Type does not exist */ + offset += sizeof(ad->len); /**< Skip this entry */ + continue; /**< Goto the next item */ + } + + offset += sizeof(ad->len) + ad->len; + if (offset > len) + return false; /**< Incomplete AD Data */ + + cb(ad, context); + }; + + return true; +} + +static void adv_data_parsed(adv_data_t* data, void* context) +{ + +} + +bt_status_t bt_pa_sync_parse_adv_data(bt_pa_sync_info_t* info, const ble_scan_result_t* result) +{ + bt_status_t status = BT_STATUS_NOT_FOUND; + + memset(info, 0x00, sizeof(bt_pa_sync_info_t)); + info->broadcast_id = BT_INVALID_BROADCAST_ID; + if (!advertiser_data_parse(result->adv_data, result->length, adv_data_parsed, info)) + return BT_STATUS_FAIL; + + return status; +} \ No newline at end of file diff --git a/framework/include/advertiser_data.h b/framework/include/advertiser_data.h index 649e9ef95..37ed639f8 100644 --- a/framework/include/advertiser_data.h +++ b/framework/include/advertiser_data.h @@ -105,6 +105,16 @@ typedef struct advertiser_data_ advertiser_data_t; */ typedef void (*ad_dump_cb_t)(const char* str); +/** + * @brief Advertising data parsing callback function. + * + * Function prototype for parsing advertising data. + * + * @param data - The parsed advertising data + * @param context - User context + */ +typedef void (*ad_parse_cb_t)(const adv_data_t* data, void* context); + /** * @brief Dump advertising data. * @@ -131,6 +141,19 @@ static void on_scan_result_cb(bt_scanner_t* scanner, ble_scan_result_t* result) */ bool advertiser_data_dump(uint8_t* data, uint16_t len, ad_dump_cb_t dump); +/** + * @brief Parse advertising data. + * + * @param data - Pointer to the advertising data buffer + * @param len - Length of the advertising data buffer + * @param cb - Callback function to output the parsed data + * @param context - User context to be carried in `cb` + * + * @return true - Parsing and output were successful + * @return false - Parsing failed + */ +bool advertiser_data_parse(const uint8_t* data, uint8_t len, ad_parse_cb_t cb, void* context); + /** * @brief Create a new advertiser data object. * diff --git a/framework/socket/bt_pa_sync.c b/framework/socket/bt_pa_sync.c new file mode 100644 index 000000000..630c038ef --- /dev/null +++ b/framework/socket/bt_pa_sync.c @@ -0,0 +1,17 @@ +/**************************************************************************** + * Copyright (C) 2025 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. + ***************************************************************************/ + +#include "bt_pa_sync.h" From 6dd6be5512aa559a55928bcb1f39602bf97414ff Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 11/16] PA sync: allow to parse scan result at SAL bug: v/82275 Add TxPower, Periodic Advertising Interval, and correct the conversion of adv_type. Signed-off-by: Zihao Gao --- framework/common/advertiser_data_helper.c | 4 +- framework/include/bt_le_scan.h | 7 +- service/src/scan_manager.c | 2 +- service/src/scan_manager.h | 2 +- service/stacks/zephyr/sal_le_scan_interface.c | 83 +++++++++++++------ 5 files changed, 67 insertions(+), 31 deletions(-) diff --git a/framework/common/advertiser_data_helper.c b/framework/common/advertiser_data_helper.c index 17598008c..b7621f0f7 100644 --- a/framework/common/advertiser_data_helper.c +++ b/framework/common/advertiser_data_helper.c @@ -247,12 +247,10 @@ static void adv_data_parsed(adv_data_t* data, void* context) bt_status_t bt_pa_sync_parse_adv_data(bt_pa_sync_info_t* info, const ble_scan_result_t* result) { - bt_status_t status = BT_STATUS_NOT_FOUND; - memset(info, 0x00, sizeof(bt_pa_sync_info_t)); info->broadcast_id = BT_INVALID_BROADCAST_ID; if (!advertiser_data_parse(result->adv_data, result->length, adv_data_parsed, info)) return BT_STATUS_FAIL; - return status; + return result->interval ? BT_STATUS_SUCCESS : BT_STATUS_NOT_FOUND; } \ No newline at end of file diff --git a/framework/include/bt_le_scan.h b/framework/include/bt_le_scan.h index c34abf2f2..4fe1e42c4 100644 --- a/framework/include/bt_le_scan.h +++ b/framework/include/bt_le_scan.h @@ -79,10 +79,13 @@ typedef enum { typedef struct { bt_address_t addr; uint8_t dev_type; /* bt_device_type_t */ - int8_t rssi; + int8_t rssi; /* RSSI in dBm (-127, +20). 0x7F if unavailable */ uint8_t addr_type; /* ble_addr_type_t */ uint8_t adv_type; /* ble_adv_type_t */ - uint8_t length; + uint8_t length; /* length of `adv_data` */ + uint8_t sid; /* advertising set identifier, valid from 0x00 to 0x0F, 0xFF if not provided */ + uint16_t interval; /* periodic advertising interval in 1.25 milliseconds, 0 if not presented */ + int8_t tx_power; /* transmit power of the advertiser in dBm (-127, +20). 0x7F if unavailable */ uint8_t pad[1]; uint8_t adv_data[1]; } ble_scan_result_t; diff --git a/service/src/scan_manager.c b/service/src/scan_manager.c index 55d867207..bfa848159 100644 --- a/service/src/scan_manager.c +++ b/service/src/scan_manager.c @@ -459,7 +459,7 @@ void scan_on_state_changed(uint8_t state) BT_LOGD("%s, state:%d", __func__, state); } -void scan_on_result_data_update(ble_scan_result_t* result_info, char* adv_data) +void scan_on_result_data_update(ble_scan_result_t* result_info, const uint8_t* adv_data) { ble_scan_result_t* result = malloc(sizeof(ble_scan_result_t) + result_info->length); diff --git a/service/src/scan_manager.h b/service/src/scan_manager.h index 4c86199ef..4795702b6 100644 --- a/service/src/scan_manager.h +++ b/service/src/scan_manager.h @@ -26,7 +26,7 @@ enum scan_state { }; void scan_on_state_changed(uint8_t state); -void scan_on_result_data_update(ble_scan_result_t* result_info, char* adv_data); +void scan_on_result_data_update(ble_scan_result_t* result_info, const uint8_t* adv_data); bt_scanner_t* scanner_start_scan(void* remote, const scanner_callbacks_t* cbs); bt_scanner_t* scanner_start_scan_settings(void* remote, ble_scan_settings_t* settings, diff --git a/service/stacks/zephyr/sal_le_scan_interface.c b/service/stacks/zephyr/sal_le_scan_interface.c index c79d72e2c..3a03227f9 100644 --- a/service/stacks/zephyr/sal_le_scan_interface.c +++ b/service/stacks/zephyr/sal_le_scan_interface.c @@ -38,11 +38,6 @@ typedef struct { sal_func_t func; } sal_scan_req_t; -typedef struct { - char value[256]; - uint8_t length; -} le_eir_data_t; - static struct bt_le_scan_param scan_param; static sal_scan_req_t* sal_scan_req(bt_controller_id_t id, sal_func_t func) @@ -85,41 +80,81 @@ static bt_status_t sal_send_req(sal_scan_req_t* req) return BT_STATUS_SUCCESS; } -static bool zblue_on_eir_found(struct bt_data* data, void* user_data) +static ble_adv_type_t parse_adv_type(const struct bt_le_scan_recv_info* info) { - le_eir_data_t* eir = user_data; + switch (info->adv_type) { + case BT_GAP_ADV_TYPE_ADV_IND: + return BT_LE_ADV_IND; + case BT_GAP_ADV_TYPE_ADV_DIRECT_IND: + return BT_LE_ADV_DIRECT_IND; + case BT_GAP_ADV_TYPE_ADV_SCAN_IND: + return BT_LE_ADV_SCAN_IND; + case BT_GAP_ADV_TYPE_ADV_NONCONN_IND: + return BT_LE_ADV_NONCONN_IND; + case BT_GAP_ADV_TYPE_SCAN_RSP: + return BT_LE_SCAN_RSP; + case BT_GAP_ADV_TYPE_EXT_ADV: + break; /**< Determined via `info->adv_props` */ + default: + break; /**< Unrecognized */ + } - eir->value[eir->length++] = data->data_len + 1; - eir->value[eir->length++] = data->type; - memcpy(&eir->value[eir->length], data->data, data->data_len); - eir->length += data->data_len; - return true; + if (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) + return BT_LE_EXT_SCAN_RSP; + if (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) + return BT_LE_EXT_ADV_DIRECT_IND; + if (!(info->adv_props & (BT_GAP_ADV_PROP_CONNECTABLE | BT_GAP_ADV_PROP_SCANNABLE))) + return BT_LE_EXT_ADV_NONCONN_IND; + if (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) + return BT_LE_EXT_ADV_SCAN_IND; + if (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) + return BT_LE_EXT_ADV_IND; + + return BT_LE_EXT_ADV_IND; /**< Unknown */ } -static void zblue_on_device_found(const bt_addr_le_t* addr, int8_t rssi, uint8_t type, struct net_buf_simple* ad) +static void scan_recv_cb(const struct bt_le_scan_recv_info* info, struct net_buf_simple* ad) { ble_scan_result_t result_info = { 0 }; - le_eir_data_t eir = { 0 }; - bt_data_parse(ad, zblue_on_eir_found, &eir); - - result_info.length = eir.length; - result_info.adv_type = type; - result_info.rssi = rssi; result_info.dev_type = BT_DEVICE_DEVTYPE_BLE; - result_info.addr_type = addr->type; - memcpy(&result_info.addr, &addr->a, sizeof(result_info.addr)); - - scan_on_result_data_update(&result_info, eir.value); + result_info.adv_type = parse_adv_type(info); + result_info.length = ad->len; + result_info.rssi = info->rssi; + result_info.tx_power = info->tx_power; + result_info.sid = info->sid; + result_info.interval = info->interval; + result_info.addr_type = info->addr->type; + memcpy(&result_info.addr, &info->addr->a, sizeof(result_info.addr)); + + scan_on_result_data_update(&result_info, ad->data); } +static struct bt_le_scan_cb scan_cbs = { + .recv = scan_recv_cb, + .timeout = NULL, +}; + static void STACK_CALL(start_scan)(void* args) { - SAL_CHECK(bt_le_scan_start(&scan_param, zblue_on_device_found), 0); + int err; + + err = bt_le_scan_cb_register(&scan_cbs); + if (err != 0 && err != -EEXIST) { + BT_LOGE("%s, register failed, ret = %d", __func__, err); + return; + } + + err = bt_le_scan_start(&scan_param, NULL); + if (err) { + BT_LOGE("%s, failed, ret = %d", __func__, err); + bt_le_scan_cb_unregister(&scan_cbs); + } } static void STACK_CALL(stop_scan)(void* args) { + bt_le_scan_cb_unregister(&scan_cbs); SAL_CHECK(bt_le_scan_stop(), 0); } From 99037c40609a0654cdefa7002a3d66edec83f2cc Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 12/16] PA sync: parse scan result for bttool bug: v/82379 Parse scan result at bttol to check if there is an Auracast source available. Signed-off-by: Zihao Gao --- framework/common/advertiser_data_helper.c | 56 +++++++++++++++++++++-- framework/include/bt_pa_sync.h | 9 ++-- framework/include/bt_uuid.h | 1 + tools/auracast_sink.c | 10 +++- 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/framework/common/advertiser_data_helper.c b/framework/common/advertiser_data_helper.c index b7621f0f7..1c848c6ab 100644 --- a/framework/common/advertiser_data_helper.c +++ b/framework/common/advertiser_data_helper.c @@ -17,8 +17,11 @@ #include #include "advertiser_data.h" -#include "bt_pa_sync.h" #include "bt_debug.h" +#ifdef CONFIG_BLUETOOTH_PA_SYNC +#include "bt_pa_sync.h" +#endif +#include "bt_utils.h" typedef struct { uint8_t ad_type; @@ -240,9 +243,55 @@ bool advertiser_data_parse(const uint8_t* data, uint8_t len, ad_parse_cb_t cb, v return true; } -static void adv_data_parsed(adv_data_t* data, void* context) +#ifdef CONFIG_BLUETOOTH_PA_SYNC +static void adv_data_parse_uuid_16(bt_pa_sync_info_t* info, uint16_t uuid_16, + const adv_data_t* data) { + const uint8_t* p = data->data + sizeof(uint16_t); + switch (uuid_16) { +#ifdef CONFIG_BLUETOOTH_AURACAST_SINK + case BT_UUID_BROADCAST_AUDIO_ANNOUNCEMENT: + if (data->len < 1 + sizeof(uuid_16) + 3) + break; /* less than AD Type (1 octet) + UUID16 (2 octets) + Broadcast ID (3 octets)*/ + + STREAM_TO_UINT24(info->broadcast_id, p); + break; +#endif + default: + break; + } +} + +static void adv_data_parsed(const adv_data_t* data, void* context) +{ + bt_pa_sync_info_t* info = (bt_pa_sync_info_t*)context; + const uint8_t* p = data->data; + uint16_t uuid_16; + + switch (data->type) { + case BT_AD_NAME_SHORT: + case BT_AD_NAME_COMPLETE: + strlcpy(info->name, (char*)data->data, MIN(sizeof(info->name), data->len)); + break; + +#ifdef CONFIG_BLUETOOTH_AURACAST_SINK + case BT_AD_BROADCAST_NAME: + strlcpy(info->broadcast_name, (char*)data->data, + MIN(sizeof(info->broadcast_name), data->len)); + break; +#endif + + case BT_AD_SERVICE_DATA16: + if (data->len < 1 + sizeof(uuid_16)) + break; /**< less than AD Type (1 octet) + UUID16 (2 octets) */ + + STREAM_TO_UINT16(uuid_16, p); + adv_data_parse_uuid_16(info, uuid_16, data); + break; + default: + break; + } } bt_status_t bt_pa_sync_parse_adv_data(bt_pa_sync_info_t* info, const ble_scan_result_t* result) @@ -253,4 +302,5 @@ bt_status_t bt_pa_sync_parse_adv_data(bt_pa_sync_info_t* info, const ble_scan_re return BT_STATUS_FAIL; return result->interval ? BT_STATUS_SUCCESS : BT_STATUS_NOT_FOUND; -} \ No newline at end of file +} +#endif /* CONFIG_BLUETOOTH_PA_SYNC */ diff --git a/framework/include/bt_pa_sync.h b/framework/include/bt_pa_sync.h index 40cd29c1e..387b0265f 100644 --- a/framework/include/bt_pa_sync.h +++ b/framework/include/bt_pa_sync.h @@ -30,16 +30,13 @@ extern "C" { * @brief Information about the periodic advertising sync. */ typedef struct bt_pa_sync_info { - /** Advertising Set ID (SID) subfield of the `AdvDataInfo` (ADI) */ - uint8_t sid; - - /** TxPower in dBm (-127 to +20). 0x7F if unavailable */ - int8_t tx_power; - /** Present if available: Broadcast_ID from Broadcast Audio Announcement. * Otherwise, `BT_INVALID_BROADCAST_ID` */ uint32_t broadcast_id; + /** UTF-8 string of the remote device name */ + char name[BT_REM_NAME_MAX_LEN + 1]; + /** UTF-8 string of the `Broadcast_Name` field in `AdvData` (if present) */ char broadcast_name[BT_BROADCAST_NAME_MAX_LEN + 1]; } bt_pa_sync_info_t; diff --git a/framework/include/bt_uuid.h b/framework/include/bt_uuid.h index c8e12eed1..d137b50c8 100644 --- a/framework/include/bt_uuid.h +++ b/framework/include/bt_uuid.h @@ -31,6 +31,7 @@ extern "C" { #define BT_UUID_A2DP_SNK 0x110B #define BT_UUID_HFP 0x111E #define BT_UUID_HFP_AG 0x111F +#define BT_UUID_BROADCAST_AUDIO_ANNOUNCEMENT 0x1852 typedef enum { BT_UUID16_TYPE = 2, diff --git a/tools/auracast_sink.c b/tools/auracast_sink.c index 88aff2a32..ebf520174 100644 --- a/tools/auracast_sink.c +++ b/tools/auracast_sink.c @@ -53,7 +53,15 @@ static void on_scan_result(bt_scanner_t* scanner, ble_scan_result_t* result) status = bt_pa_sync_parse_adv_data(info, result); if (status != BT_STATUS_SUCCESS) - return; + goto exit; + + PRINT("%s, device name = %s, broadcast name = %s, id = %" PRIu32 ", sid = %d, " + "txpower = %d dBm, rssi = %d dBm", + __func__, info->name, info->broadcast_name, info->broadcast_id, result->sid, + result->tx_power, result->rssi); + +exit: + free(info); } static void on_scan_status(bt_scanner_t* scanner, uint8_t status) From 99b396b661e2e6ad5fc0e14f83b7a06c4cc1a514 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 13/16] PA sync: optimize logs at bttool. bug: v/82379 Skip logs that are not available. Add more debug logs on error. Signed-off-by: Zihao Gao --- tools/auracast_sink.c | 50 ++++++++++++++++++++++++++++++++++++------- tools/utils.h | 9 ++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/tools/auracast_sink.c b/tools/auracast_sink.c index ebf520174..feb78704a 100644 --- a/tools/auracast_sink.c +++ b/tools/auracast_sink.c @@ -18,6 +18,7 @@ #include "bt_pa_sync.h" #include "bt_tools.h" +#define BTTOOL_AURACAST_SINK_LOG_SIZE (256) typedef struct { bt_scanner_t* scanner; } bttool_auracast_sink_t; @@ -42,7 +43,9 @@ static void usage(void) static void on_scan_result(bt_scanner_t* scanner, ble_scan_result_t* result) { bt_status_t status; - bt_pa_sync_info_t* info; + bt_pa_sync_info_t* info = NULL; + char* log = NULL; + size_t size = BTTOOL_AURACAST_SINK_LOG_SIZE; if (g_auracast_sink->scanner != scanner) return; @@ -55,20 +58,44 @@ static void on_scan_result(bt_scanner_t* scanner, ble_scan_result_t* result) if (status != BT_STATUS_SUCCESS) goto exit; - PRINT("%s, device name = %s, broadcast name = %s, id = %" PRIu32 ", sid = %d, " - "txpower = %d dBm, rssi = %d dBm", - __func__, info->name, info->broadcast_name, info->broadcast_id, result->sid, - result->tx_power, result->rssi); + log = zalloc(size); /**< for print log */ + if (!log) + goto exit; + + BTTOOL_STRCAT(log, size, "%s", __func__); + + if (info->name[0] != '\0') + BTTOOL_STRCAT(log, size, ", device:%s", info->name); + + if (info->broadcast_name[0] != '\0') + BTTOOL_STRCAT(log, size, ", broadcast name:%s", info->broadcast_name); + + if (info->broadcast_id != BT_INVALID_BROADCAST_ID) + BTTOOL_STRCAT(log, size, ", id:0x%06" PRIx32, info->broadcast_id); + + if (result->sid != 0xFF) + BTTOOL_STRCAT(log, size, ", sid:0x%x", result->sid); + + if (result->tx_power != 0x7F) + BTTOOL_STRCAT(log, size, ", txpower:%d", result->tx_power); + + if (result->rssi != 0x7F) + BTTOOL_STRCAT(log, size, ", rssi:%d", result->rssi); + PRINT("%s", log); exit: free(info); + free(log); } static void on_scan_status(bt_scanner_t* scanner, uint8_t status) { PRINT("%s, status = %d", __func__, status); - if (g_auracast_sink->scanner != scanner) + + if (g_auracast_sink->scanner != scanner) { + PRINT("%s, scanner(%p) mismatch", __func__, scanner); return; + } if (status != BT_STATUS_SUCCESS) g_auracast_sink->scanner = NULL; @@ -77,8 +104,11 @@ static void on_scan_status(bt_scanner_t* scanner, uint8_t status) static void on_scan_stopped(bt_scanner_t* scanner) { PRINT("%s", __func__); - if (g_auracast_sink->scanner != scanner) + + if (g_auracast_sink->scanner != scanner) { + PRINT("%s, scanner(%p) mismatch", __func__, scanner); return; + } g_auracast_sink->scanner = NULL; } @@ -110,8 +140,12 @@ int scan_cmd(void* handle, int argc, char* argv[]) memcpy(&settings, &default_scan_settings, sizeof(settings)); g_auracast_sink->scanner = bt_le_start_scan_settings(handle, &settings, &scanner_cbs); - if (g_auracast_sink->scanner == NULL) + if (g_auracast_sink->scanner == NULL) { + PRINT("Failed to start a scan"); return CMD_ERROR; + } + + PRINT("Starting scan, scanner = %p", g_auracast_sink->scanner); return CMD_OK; } diff --git a/tools/utils.h b/tools/utils.h index e12424f03..eb4eadb95 100644 --- a/tools/utils.h +++ b/tools/utils.h @@ -19,6 +19,15 @@ #include "bluetooth.h" +#define BTTOOL_STRCAT(dst, size, src, ...) \ + do { \ + size_t _len = strlen(dst); \ + size_t _size = (size); \ + if (_len + 1 >= _size) \ + break; \ + snprintf(dst + _len, _size - _len, src, ##__VA_ARGS__); \ + } while (0) + bool phy_is_vaild(uint8_t phy); int le_addr_type(const char* str, ble_addr_type_t* type); bool bttool_allocator(void** data, uint32_t size); From f75ec6667441c6dca386e189c92de11df00c36b7 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 09:57:31 +0800 Subject: [PATCH 14/16] PA sync: allow to stop scan bug: v/82379 Allow to stop scanning for periodic advertisers. Signed-off-by: Zihao Gao --- tools/auracast_sink.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/tools/auracast_sink.c b/tools/auracast_sink.c index feb78704a..d4bd4fa39 100644 --- a/tools/auracast_sink.c +++ b/tools/auracast_sink.c @@ -23,11 +23,13 @@ typedef struct { bt_scanner_t* scanner; } bttool_auracast_sink_t; -static int scan_cmd(void* handle, int argc, char* argv[]); +static int scan_start_cmd(void* handle, int argc, char* argv[]); +static int scan_stop_cmd(void* handle, int argc, char* argv[]); static bttool_auracast_sink_t* g_auracast_sink = NULL; static bt_command_t g_auracast_sink_tables[] = { - { "scan", scan_cmd, 0, "\"Search for nearby Auracast sources\"" }, + { "scan", scan_start_cmd, 0, "\"Search for nearby Auracast sources\"" }, + { "stopscan", scan_stop_cmd, 0, "\"Stop searching\"" }, }; static void usage(void) @@ -47,7 +49,7 @@ static void on_scan_result(bt_scanner_t* scanner, ble_scan_result_t* result) char* log = NULL; size_t size = BTTOOL_AURACAST_SINK_LOG_SIZE; - if (g_auracast_sink->scanner != scanner) + if (!g_auracast_sink || g_auracast_sink->scanner != scanner) return; info = malloc(sizeof(bt_pa_sync_info_t)); @@ -92,7 +94,7 @@ static void on_scan_status(bt_scanner_t* scanner, uint8_t status) { PRINT("%s, status = %d", __func__, status); - if (g_auracast_sink->scanner != scanner) { + if (!g_auracast_sink || g_auracast_sink->scanner != scanner) { PRINT("%s, scanner(%p) mismatch", __func__, scanner); return; } @@ -105,7 +107,7 @@ static void on_scan_stopped(bt_scanner_t* scanner) { PRINT("%s", __func__); - if (g_auracast_sink->scanner != scanner) { + if (!g_auracast_sink || g_auracast_sink->scanner != scanner) { PRINT("%s, scanner(%p) mismatch", __func__, scanner); return; } @@ -128,10 +130,15 @@ static const ble_scan_settings_t default_scan_settings = { .policy.policy = 0, /**< Unfiltered */ }; -int scan_cmd(void* handle, int argc, char* argv[]) +int scan_start_cmd(void* handle, int argc, char* argv[]) { ble_scan_settings_t settings; + if (!g_auracast_sink) { + PRINT("Not initialized"); + return CMD_INVALID_OPT; + } + if (g_auracast_sink->scanner) { PRINT("Already scanning"); return CMD_USAGE_FAULT; @@ -150,6 +157,26 @@ int scan_cmd(void* handle, int argc, char* argv[]) return CMD_OK; } +int scan_stop_cmd(void* handle, int argc, char* argv[]) +{ + if (!g_auracast_sink) { + PRINT("Not initialized"); + return CMD_INVALID_OPT; + } + + if (!g_auracast_sink->scanner) { + PRINT("Not scanning"); + return CMD_USAGE_FAULT; + } + + PRINT("Stop scan, scanner = %p", g_auracast_sink->scanner); + + bt_le_stop_scan(handle, g_auracast_sink->scanner); + g_auracast_sink->scanner = NULL; + + return CMD_OK; +} + int auracast_sink_command_init(void* handle) { g_auracast_sink = zalloc(sizeof(bttool_auracast_sink_t)); @@ -161,6 +188,9 @@ int auracast_sink_command_init(void* handle) void auracast_sink_command_uninit(void* handle) { + if (!g_auracast_sink) + return; + free(g_auracast_sink); g_auracast_sink = NULL; } From 736fc6461a2c38485950ced223cd9daf9e87caaa Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 15:28:48 +0800 Subject: [PATCH 15/16] PA sync: add flags in scan result bug: v/82820 Add an extra flag to indicate whether periodic advertising is present in the scan result. Signed-off-by: Zihao Gao --- framework/common/advertiser_data_helper.c | 4 +++- framework/include/bt_le_scan.h | 4 +++- service/src/scan_manager.c | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/framework/common/advertiser_data_helper.c b/framework/common/advertiser_data_helper.c index 1c848c6ab..11a462ad3 100644 --- a/framework/common/advertiser_data_helper.c +++ b/framework/common/advertiser_data_helper.c @@ -301,6 +301,8 @@ bt_status_t bt_pa_sync_parse_adv_data(bt_pa_sync_info_t* info, const ble_scan_re if (!advertiser_data_parse(result->adv_data, result->length, adv_data_parsed, info)) return BT_STATUS_FAIL; - return result->interval ? BT_STATUS_SUCCESS : BT_STATUS_NOT_FOUND; + return result->flags & SCAN_RESULT_FLAG_PERIODIC_ADVERTISING + ? BT_STATUS_SUCCESS + : BT_STATUS_NOT_FOUND; } #endif /* CONFIG_BLUETOOTH_PA_SYNC */ diff --git a/framework/include/bt_le_scan.h b/framework/include/bt_le_scan.h index 4fe1e42c4..eec5b0ce3 100644 --- a/framework/include/bt_le_scan.h +++ b/framework/include/bt_le_scan.h @@ -65,6 +65,8 @@ enum { #define SCAN_MODE_LOW_LATENCY_INTERVAL 0xA0 #define SCAN_MODE_LOW_LATENCY_WINDOW 0xA0 +#define SCAN_RESULT_FLAG_PERIODIC_ADVERTISING 0x01 + typedef void bt_scanner_t; typedef enum { @@ -86,7 +88,7 @@ typedef struct { uint8_t sid; /* advertising set identifier, valid from 0x00 to 0x0F, 0xFF if not provided */ uint16_t interval; /* periodic advertising interval in 1.25 milliseconds, 0 if not presented */ int8_t tx_power; /* transmit power of the advertiser in dBm (-127, +20). 0x7F if unavailable */ - uint8_t pad[1]; + uint8_t flags; /* e.g., `SCAN_RESULT_FLAG_PERIODIC_ADVERTISING` */ uint8_t adv_data[1]; } ble_scan_result_t; diff --git a/service/src/scan_manager.c b/service/src/scan_manager.c index bfa848159..993f8873d 100644 --- a/service/src/scan_manager.c +++ b/service/src/scan_manager.c @@ -470,6 +470,11 @@ void scan_on_result_data_update(ble_scan_result_t* result_info, const uint8_t* a memcpy(result, result_info, sizeof(ble_scan_result_t)); memcpy(result->adv_data, adv_data, result_info->length); + if (result->interval) + result->flags |= SCAN_RESULT_FLAG_PERIODIC_ADVERTISING; + else + result->flags &= ~SCAN_RESULT_FLAG_PERIODIC_ADVERTISING; + do_in_service_loop(notify_scanners_scan_result, result); } From d7c9c6017416107b01c2869ff001227aff30c075 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Tue, 6 Jan 2026 15:48:55 +0800 Subject: [PATCH 16/16] LE Scan: modify message codes bug: v/82820 Modify message codes so its safe when client and server have different version of codes. Signed-off-by: Zihao Gao --- service/ipc/socket/include/bt_message_scan.h | 7 +++++-- service/ipc/socket/src/bt_socket_scan.c | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/service/ipc/socket/include/bt_message_scan.h b/service/ipc/socket/include/bt_message_scan.h index f60694221..28133cfe7 100644 --- a/service/ipc/socket/include/bt_message_scan.h +++ b/service/ipc/socket/include/bt_message_scan.h @@ -26,7 +26,7 @@ BT_SCAN_MESSAGE_START, #ifdef __BT_CALLBACK_CODE__ BT_SCAN_CALLBACK_START, - BT_LE_ON_SCAN_RESULT, + BT_LE_ON_SCAN_RESULT_UNUSED, // Unused, but kept to maintain enum stability BT_LE_ON_SCAN_START_STATUS, BT_LE_ON_SCAN_STOPPED, BT_SCAN_CALLBACK_END, @@ -46,7 +46,9 @@ BT_SCAN_MESSAGE_START, enum { BLE_SCAN_SUBCODE_START = 0, - BLE_SCAN_SUBCODE_BATCH_SCAN_CALLBACK = 1, + BLE_SCAN_SUBCODE_BATCH_SCAN_CALLBACK_UNUSED = 1, // Unused + BLE_SCAN_SUBCODE_SCAN_CALLBACK = 2, + BLE_SCAN_SUBCODE_BATCH_SCAN_CALLBACK = 3, BLE_SCAN_SUBCODE_END = BT_IPC_CODE_SUBCODE_MAX_NUM, }; @@ -56,6 +58,7 @@ BT_SCAN_MESSAGE_START, #define BT_IPC_CODE_CALLBACK_BLE_SCAN_BEGIN BT_IPC_CODE(BT_IPC_CODE_TYPE_CALLBACK, BT_IPC_CODE_GROUP_BLE_SCAN, 0) // TODO: Add new BT IPC Code sequentially +#define BT_LE_ON_SCAN_RESULT BT_IPC_CODE(BT_IPC_CODE_TYPE_CALLBACK, BT_IPC_CODE_GROUP_BLE_SCAN, BLE_SCAN_SUBCODE_SCAN_CALLBACK) #define BT_LE_ON_BATCH_SCAN_RESULT BT_IPC_CODE(BT_IPC_CODE_TYPE_CALLBACK, BT_IPC_CODE_GROUP_BLE_SCAN, BLE_SCAN_SUBCODE_BATCH_SCAN_CALLBACK) #define BT_IPC_CODE_CALLBACK_BLE_SCAN_END BT_IPC_CODE(BT_IPC_CODE_TYPE_CALLBACK, BT_IPC_CODE_GROUP_BLE_SCAN, BT_IPC_CODE_SUBCODE_MAX_NUM) diff --git a/service/ipc/socket/src/bt_socket_scan.c b/service/ipc/socket/src/bt_socket_scan.c index fbd50a939..337a11ab4 100644 --- a/service/ipc/socket/src/bt_socket_scan.c +++ b/service/ipc/socket/src/bt_socket_scan.c @@ -271,14 +271,7 @@ int bt_socket_client_scan_callback(service_poll_t* poll, int fd, bt_instance_t* ins, bt_message_packet_t* packet, bool is_async) { switch (packet->code) { - case BT_LE_ON_SCAN_RESULT: { - bt_scan_remote_t* scan = INT2PTR(bt_scan_remote_t*) packet->scan_cb._on_scan_result_cb.scanner; - ble_scan_result_t* result = &packet->scan_cb._on_scan_result_cb.result; - ble_scan_result_t* tmp = malloc(sizeof(ble_scan_result_t) + result->length); - memcpy(tmp, result, sizeof(ble_scan_result_t)); - memcpy(tmp->adv_data, packet->scan_cb._on_scan_result_cb.adv_data, result->length); - scan->callback->on_scan_result(scan, tmp); - free(tmp); + case BT_LE_ON_SCAN_RESULT_UNUSED: { break; } case BT_LE_ON_SCAN_START_STATUS: { @@ -320,6 +313,16 @@ int bt_socket_client_scan_callback(service_poll_t* poll, } break; } + case BLE_SCAN_SUBCODE_SCAN_CALLBACK: { + bt_scan_remote_t* scan = INT2PTR(bt_scan_remote_t*) packet->scan_cb._on_scan_result_cb.scanner; + ble_scan_result_t* result = &packet->scan_cb._on_scan_result_cb.result; + ble_scan_result_t* tmp = malloc(sizeof(ble_scan_result_t) + result->length); + memcpy(tmp, result, sizeof(ble_scan_result_t)); + memcpy(tmp->adv_data, packet->scan_cb._on_scan_result_cb.adv_data, result->length); + scan->callback->on_scan_result(scan, tmp); + free(tmp); + break; + } default: return BT_STATUS_PARM_INVALID; }