268 lines
9.5 KiB
C
268 lines
9.5 KiB
C
|
||
#include "system/app_core.h"
|
||
#include "system/includes.h"
|
||
#include "btstack/btstack_task.h"
|
||
#include "btstack/bluetooth.h"
|
||
#include "le_common.h"
|
||
#include "ble_user.h"
|
||
|
||
#if 0 //ENABLE_THIS_TEST
|
||
|
||
#define LOG_TAG_CONST EARPHONE
|
||
#define LOG_TAG "[BLE_TEST]"
|
||
#define LOG_ERROR_ENABLE
|
||
#define LOG_DEBUG_ENABLE
|
||
#define LOG_INFO_ENABLE
|
||
#include "debug.h"
|
||
|
||
// =================== 配置区 START ===================
|
||
|
||
// 1. 设置要连接的目标从机设备蓝牙名称
|
||
#define TARGET_BLE_NAME "CM-22222"
|
||
|
||
// 2. 设置要搜索的 Service UUID 和 Characteristic UUID
|
||
// Service UUID: 0x180D
|
||
#define TARGET_SERVICE_UUID16 0x180D
|
||
// Characteristic UUID: 0x2A37 (Notify)
|
||
#define TARGET_CHARACTERISTIC_UUID16 0x2A37
|
||
#define TARGET_CHARACTERISTIC_OPT_TYPE ATT_PROPERTY_NOTIFY
|
||
|
||
// =================== 配置区 END =====================
|
||
|
||
// ATT RAM buffer
|
||
#define ATT_LOCAL_MTU_SIZE (517)
|
||
#define ATT_SEND_CBUF_SIZE (256)
|
||
#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE)
|
||
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
|
||
|
||
// Profile 搜索 buffer
|
||
#define SEARCH_PROFILE_BUFSIZE (512)
|
||
static u8 search_ram_buffer[SEARCH_PROFILE_BUFSIZE] __attribute__((aligned(4)));
|
||
|
||
// BLE 工作状态
|
||
static u8 ble_work_state = 0;
|
||
static hci_con_handle_t con_handle;
|
||
|
||
// 搜索到的目标特征值句柄
|
||
static u16 target_write_handle = 0;
|
||
static u16 target_notify_handle = 0;
|
||
|
||
// 函数前向声明
|
||
static int ble_central_test_scan_enable(u32 en);
|
||
static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||
|
||
|
||
// 设置 BLE 工作状态
|
||
static void set_ble_work_state(u8 state) {
|
||
if (state != ble_work_state) {
|
||
log_info("ble_work_state: %d -> %d\n", ble_work_state, state);
|
||
ble_work_state = state;
|
||
}
|
||
}
|
||
|
||
// 解析广播数据,寻找目标设备
|
||
static bool resolve_adv_report(u8 *adv_address, u8 data_length, u8 *data) {
|
||
u8 i, length, ad_type;
|
||
u8 *adv_data_ptr = data;
|
||
|
||
for (i = 0; i < data_length;) {
|
||
if (*adv_data_ptr == 0) {
|
||
break;
|
||
}
|
||
|
||
length = *adv_data_ptr++;
|
||
ad_type = *adv_data_ptr++;
|
||
i += (length + 1);
|
||
|
||
if (ad_type == HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME || ad_type == HCI_EIR_DATATYPE_SHORTENED_LOCAL_NAME) {
|
||
if (length > 1 && (0 == memcmp(adv_data_ptr, TARGET_BLE_NAME, strlen(TARGET_BLE_NAME)))) {
|
||
log_info("Found target device: %s", TARGET_BLE_NAME);
|
||
log_info_hexdump(adv_address, 6);
|
||
return true;
|
||
}
|
||
}
|
||
adv_data_ptr += (length - 1);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// 创建连接
|
||
static void central_test_create_connection(u8 *addr, u8 addr_type) {
|
||
if (ble_work_state >= BLE_ST_CREATE_CONN) {
|
||
return;
|
||
}
|
||
log_info("Stopping scan...");
|
||
ble_central_test_scan_enable(0);
|
||
|
||
struct create_conn_param_t conn_param = {0};
|
||
conn_param.conn_interval = 24;
|
||
conn_param.conn_latency = 0;
|
||
conn_param.supervision_timeout = 600;
|
||
conn_param.peer_address_type = addr_type;
|
||
memcpy(conn_param.peer_address, addr, 6);
|
||
|
||
set_ble_work_state(BLE_ST_CREATE_CONN);
|
||
ble_op_create_connection(&conn_param);
|
||
}
|
||
|
||
// 开始搜索 Profile
|
||
static void central_test_search_profile() {
|
||
target_write_handle = 0;
|
||
target_notify_handle = 0;
|
||
user_client_init(con_handle, search_ram_buffer, SEARCH_PROFILE_BUFSIZE);
|
||
ble_op_search_profile_all();
|
||
}
|
||
|
||
// 搜索 Profile 结果回调
|
||
void user_client_report_search_result(search_result_t *result_info) {
|
||
if (result_info == (void *)-1) {
|
||
log_info("Search profile complete.");
|
||
set_ble_work_state(BLE_ST_SEARCH_COMPLETE);
|
||
// 如果找到了 NOTIFY 特征,使能它
|
||
if (target_notify_handle) {
|
||
log_info("Enabling notification for handle 0x%04x", target_notify_handle);
|
||
u16 val = 0x0001;
|
||
ble_op_att_send_data(target_notify_handle + 1, &val, 2, ATT_OP_WRITE);
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (result_info->services.uuid16 == TARGET_SERVICE_UUID16 &&
|
||
result_info->characteristic.uuid16 == TARGET_CHARACTERISTIC_UUID16) {
|
||
log_info("Found target characteristic UUID 0x%04x", TARGET_CHARACTERISTIC_UUID16);
|
||
if ((result_info->characteristic.properties & ATT_PROPERTY_WRITE_WITHOUT_RESPONSE) ||
|
||
(result_info->characteristic.properties & ATT_PROPERTY_WRITE)) {
|
||
target_write_handle = result_info->characteristic.value_handle;
|
||
log_info("Found write handle: 0x%04x", target_write_handle);
|
||
}
|
||
if (result_info->characteristic.properties & ATT_PROPERTY_NOTIFY) {
|
||
target_notify_handle = result_info->characteristic.value_handle;
|
||
log_info("Found notify handle: 0x%04x", target_notify_handle);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 接收到数据回调
|
||
void user_client_report_data_callback(att_data_report_t *report_data) {
|
||
log_info("RX data, handle=0x%04x, len=%d:", report_data->value_handle, report_data->blob_length);
|
||
log_info_hexdump(report_data->blob, report_data->blob_length);
|
||
}
|
||
|
||
// BLE 事件回调处理
|
||
static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
|
||
switch (packet_type) {
|
||
case HCI_EVENT_PACKET:
|
||
switch (hci_event_packet_get_type(packet)) {
|
||
case HCI_EVENT_LE_META:
|
||
switch (hci_event_le_meta_get_subevent_code(packet)) {
|
||
case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE:
|
||
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
|
||
if (hci_subevent_le_connection_complete_get_status(packet)) {
|
||
log_error("Connection failed, status: 0x%x", hci_subevent_le_connection_complete_get_status(packet));
|
||
set_ble_work_state(BLE_ST_CONNECT_FAIL);
|
||
ble_central_test_scan_enable(1); // 重新开始扫描
|
||
} else {
|
||
con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
|
||
log_info("Connection established, handle: 0x%04x", con_handle);
|
||
ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
|
||
set_ble_work_state(BLE_ST_CONNECT);
|
||
central_test_search_profile();
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
||
log_info("Disconnected, reason: 0x%x", hci_event_disconnection_complete_get_reason(packet));
|
||
con_handle = 0;
|
||
ble_op_att_send_init(0, NULL, 0, 0);
|
||
set_ble_work_state(BLE_ST_DISCONN);
|
||
ble_central_test_scan_enable(1); // 断开后重新扫描
|
||
break;
|
||
|
||
case GAP_EVENT_ADVERTISING_REPORT:
|
||
if (ble_work_state != BLE_ST_SCAN) {
|
||
break;
|
||
}
|
||
adv_report_t *report = (void *)&packet[2];
|
||
if (resolve_adv_report(report->address, report->length, report->data)) {
|
||
central_test_create_connection(report->address, report->address_type);
|
||
}
|
||
break;
|
||
|
||
case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
|
||
log_info("MTU exchange complete, MTU = %d", att_event_mtu_exchange_complete_get_MTU(packet));
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 启动或停止扫描
|
||
static int ble_central_test_scan_enable(u32 en) {
|
||
if (en) {
|
||
if (ble_work_state >= BLE_ST_SCAN) {
|
||
return 0; // 已经在扫描或连接中
|
||
}
|
||
log_info("Starting scan...");
|
||
set_ble_work_state(BLE_ST_SCAN);
|
||
ble_op_set_scan_param(SCAN_ACTIVE, 48, 48);
|
||
ble_op_scan_enable2(1, 0);
|
||
} else {
|
||
if (ble_work_state < BLE_ST_SCAN) {
|
||
return 0; // 已经停止
|
||
}
|
||
log_info("Stopping scan...");
|
||
set_ble_work_state(BLE_ST_IDLE);
|
||
ble_op_scan_enable2(0, 0);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// 发送数据接口
|
||
int xtell_ble_central_test_send_data(u8 *data, u16 len) {
|
||
if (!con_handle || ble_work_state != BLE_ST_SEARCH_COMPLETE) {
|
||
log_error("Not connected or profile search not complete.");
|
||
return -1;
|
||
}
|
||
if (!target_write_handle) {
|
||
log_error("No writable characteristic found.");
|
||
return -1;
|
||
}
|
||
|
||
int ret = ble_op_att_send_data(target_write_handle, data, len, ATT_OP_WRITE_WITHOUT_RESPOND);
|
||
if (ret == 0) {
|
||
log_info("TX data, len=%d:", len);
|
||
log_info_hexdump(data, len);
|
||
} else {
|
||
log_error("Failed to send data, ret=%d", ret);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
// 注册 BLE central 模式需要的回调
|
||
static void ble_central_test_register_handlers(void) {
|
||
log_info("Registering BLE central test handlers...");
|
||
// 注意:le_device_db_init() 和 ble_stack_gatt_role() 可能已被RCSP的profile_init调用
|
||
// 这里我们只覆盖 packet handlers
|
||
gatt_client_init(); // 确保 gatt client 被初始化
|
||
gatt_client_register_packet_handler(cbk_packet_handler);
|
||
hci_event_callback_set(cbk_packet_handler);
|
||
le_l2cap_register_packet_handler(cbk_packet_handler);
|
||
ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
|
||
}
|
||
|
||
// 测试总开关和初始化
|
||
void xtell_ble_central_test_start(void) {
|
||
if (ble_work_state != 0) {
|
||
log_info("Test is already running.");
|
||
return;
|
||
}
|
||
log_info("======== Xtell BLE Central Test Start ========");
|
||
set_ble_work_state(BLE_ST_INIT_OK);
|
||
ble_module_enable(1); // 使能 BLE 模块
|
||
ble_central_test_register_handlers(); // 注册我们的回调
|
||
ble_central_test_scan_enable(1); // 开始扫描
|
||
}
|
||
|
||
#endif
|