#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