/* * 极简版蓝牙主设备 * 功能:连接目标设备,发送数据,接收打印 */ #if 0 #define test 1 #include #include #include "bf0_ble_gap.h" #include "bf0_sibles.h" #define LOG_TAG "simple_ble" #include "log.h" #define TARGET_NAME_PREFIX "KEEY FOUR" // 目标设备名称前缀 #define SCAN_INTERVAL_MS 100 // 扫描间隔(ms) #define SCAN_WINDOW_MS 50 // 扫描窗口(ms) #define CONN_TIMEOUT_MS 5000 // 连接超时(ms) /* 连接状态 */ static uint8_t g_scanning = 0; static uint8_t g_connecting = 0; static uint8_t g_connected = 0; static uint8_t g_conn_idx = 0xFF; static uint16_t g_target_handle = 0x003b; // 你要用的特征句柄 /* 新增:远程服务句柄 */ static uint16_t g_remote_svc_hdl = 0; // 用于主设备模式 /** * @brief 判断是否为目标设备 */ static uint8_t is_target_device(ble_gap_ext_adv_report_ind_t *ind) { uint8_t *data = ind->data; uint16_t len = ind->length; uint8_t idx = 0; while (idx < len) { uint8_t field_len = data[idx]; uint8_t field_type = data[idx + 1]; if (field_type == 0x08 || field_type == 0x09) { char dev_name[32] = {0}; uint8_t name_len = field_len - 1; if (name_len > 31) name_len = 31; memcpy(dev_name, &data[idx + 2], name_len); LOG_I("Found device: %s", dev_name); if (strstr(dev_name, TARGET_NAME_PREFIX) != NULL) { LOG_I("Target matched!"); return 1; } break; } idx += field_len + 1; } return 0; } /** * @brief 启动连接(供外部调用) */ void simple_ble_start_connect(void) { #if 1 if (g_scanning || g_connecting) { LOG_I("Busy, try later"); return; } LOG_I("Start scanning for devices with name: %s", TARGET_NAME_PREFIX); ble_gap_scan_start_t scan_param; memset(&scan_param, 0, sizeof(scan_param)); scan_param.own_addr_type = GAPM_STATIC_ADDR; // 静态地址 scan_param.type = GAPM_SCAN_TYPE_OBSERVER; // 观察者模式 scan_param.prop = GAPM_SCAN_PROP_PHY_1M_BIT; // 只扫描1M PHY scan_param.dup_filt_pol = 0; // 不过滤重复 scan_param.scan_param_1m.scan_intv = SCAN_INTERVAL_MS * 8 / 5; // 扫描间隔 scan_param.scan_param_1m.scan_wd = SCAN_WINDOW_MS * 8 / 5; // 扫描窗口 scan_param.duration = 0; // 持续扫描 scan_param.period = 0; // 不周期扫描 ble_gap_scan_start(&scan_param); #endif } /** * @brief 连接设备 */ static void connect_device(ble_gap_addr_t *addr) { ble_gap_connection_create_param_t conn_param; memset(&conn_param, 0, sizeof(conn_param)); conn_param.own_addr_type = GAPM_STATIC_ADDR; conn_param.type = GAPM_INIT_TYPE_DIRECT_CONN_EST; conn_param.conn_to = 500; // 5秒超时 conn_param.conn_param_1m.scan_intv = 0x30; conn_param.conn_param_1m.scan_wd = 0x30; conn_param.conn_param_1m.conn_intv_max = 0x30; conn_param.conn_param_1m.conn_intv_min = 0x28; conn_param.conn_param_1m.conn_latency = 0; conn_param.conn_param_1m.supervision_to = 500; conn_param.conn_param_1m.ce_len_max = 48; conn_param.conn_param_1m.ce_len_min = 0; memcpy(&conn_param.peer_addr, addr, sizeof(ble_gap_addr_t)); g_connecting = 1; ble_gap_create_connection(&conn_param); } /** * @brief 事件处理 - 只关注连接和数据接收 */ static int simple_ble_event_handler(uint16_t event_id, uint8_t *data, uint16_t len, uint32_t context) { switch (event_id) { case BLE_GAP_SCAN_START_CNF: { ble_gap_start_scan_cnf_t *cnf = (ble_gap_start_scan_cnf_t *)data; if (cnf->status == HL_ERR_NO_ERROR) { LOG_I("Scan started"); g_scanning = 1; } break; } case BLE_GAP_EXT_ADV_REPORT_IND: { if (!g_scanning || g_connecting || g_connected) break; ble_gap_ext_adv_report_ind_t *ind = (ble_gap_ext_adv_report_ind_t *)data; if (is_target_device(ind)) { LOG_I("Target found, stopping scan..."); ble_gap_scan_stop(); connect_device(&ind->addr); } break; } case BLE_GAP_SCAN_STOPPED_IND: { ble_gap_scan_stopped_ind_t *ind = (ble_gap_scan_stopped_ind_t *)data; LOG_I("Scan stopped, reason: %d", ind->reason); g_scanning = 0; break; } case BLE_GAP_CONNECTED_IND: { ble_gap_connect_ind_t *ind = (ble_gap_connect_ind_t *)data; if (ind->role == 0) { // 主设备角色 LOG_I("*** MASTER: Connected to device! conn_idx=%d", ind->conn_idx); g_connected = 1; g_conn_idx = ind->conn_idx; /* 交换MTU */ sibles_exchange_mtu(ind->conn_idx); /* 关键:开始服务发现 */ LOG_I("Starting service discovery..."); sibles_search_service(ind->conn_idx, 0, NULL); // 发现所有服务 } break; } case BLE_GAP_DISCONNECTED_IND: { ble_gap_disconnected_ind_t *ind = (ble_gap_disconnected_ind_t *)data; g_connected = 0; g_conn_idx = 0xFF; LOG_I("Disconnected, reason=%d", ind->reason); break; } case SIBLES_SEARCH_SVC_RSP: // 这个事件ID需要从日志确认 { sibles_svc_search_rsp_t *rsp = (sibles_svc_search_rsp_t *)data; LOG_I("=== SERVICE SEARCH RESPONSE ==="); LOG_I("conn_idx=%d, result=%d", rsp->conn_idx, rsp->result); if (rsp->result == HL_ERR_NO_ERROR && rsp->svc) { LOG_I("Service found! start=0x%04X, end=0x%04X, char_count=%d", rsp->svc->hdl_start, rsp->svc->hdl_end, rsp->svc->char_count); // 打印所有特征 sibles_svc_search_char_t *chara = (sibles_svc_search_char_t *)rsp->svc->att_db; for (int i = 0; i < rsp->svc->char_count; i++) { LOG_I("Char %d: handle=0x%04X, prop=0x%02X", i, chara->pointer_hdl, chara->prop); // 如果是目标句柄 if (chara->pointer_hdl == 0x003b) { LOG_I("★★★ FOUND TARGET HANDLE 0x003b! ★★★"); g_target_handle = chara->pointer_hdl; } // 移动到下一个特征 uint16_t offset = sizeof(sibles_svc_search_char_t) + chara->desc_count * sizeof(struct sibles_disc_char_desc_ind); chara = (sibles_svc_search_char_t *)((uint8_t *)chara + offset); } // 注册远程服务 g_remote_svc_hdl = sibles_register_remote_svc( rsp->conn_idx, rsp->svc->hdl_start, rsp->svc->hdl_end, NULL ); LOG_I("Remote service handle: %d", g_remote_svc_hdl); } break; } /* ===== 数据接收 - 直接打印所有数据 ===== */ default: // 连接后,打印所有收到的事件和数据 if (g_connected) { LOG_I("RECV: event=0x%04X, len=%d", event_id, len); if (len > 0) { rt_kprintf("DATA: "); for (int i = 0; i < len && i < 32; i++) { rt_kprintf("%02X ", data[i]); } rt_kprintf("\n"); } } break; } return 0; } BLE_EVENT_REGISTER(simple_ble_event_handler, NULL); /** * @brief 启动连接 */ void simple_ble_start(void) { if (g_scanning || g_connecting) { LOG_I("Busy"); return; } LOG_I("Scanning for %s...", TARGET_NAME_PREFIX); ble_gap_scan_start_t scan_param; memset(&scan_param, 0, sizeof(scan_param)); scan_param.own_addr_type = GAPM_STATIC_ADDR; scan_param.type = GAPM_SCAN_TYPE_OBSERVER; scan_param.dup_filt_pol = 0; scan_param.scan_param_1m.scan_intv = 0x40; // 100ms scan_param.scan_param_1m.scan_wd = 0x20; // 50ms scan_param.duration = 0; // 持续扫描 scan_param.period = 0; ble_gap_scan_start(&scan_param); } /** * @brief 发送数据 - 对外接口 */ void simple_ble_send_data(uint8_t *data, uint16_t len) { //simple_ble_send(data, len); } /** * @brief 获取连接状态 */ uint8_t simple_ble_is_connected(void) { return g_connected; } /** * @brief 断开连接 */ void simple_ble_stop(void) { if (g_connected) { ble_gap_disconnect_t dis; dis.conn_idx = g_conn_idx; dis.reason = 0x13; ble_gap_disconnect(&dis); } } #endif