BT_STATUS_SUCCESS 这是什么意思

时间: 2025-09-09 08:55:31 AIGC 浏览: 4
<think> 我们之前讨论的是蓝牙安全模块中的状态码`btm_sec_cb.pairing_state`,但现在用户询问的是`BT_STATUS_SUCCESS`的含义。根据上下文,这很可能是指蓝牙开发中的状态码。 在蓝牙开发中,`BT_STATUS_SUCCESS`通常表示操作成功完成,它是一个枚举值,通常定义为0。 在Android蓝牙栈(如Bluedroid)中,常见状态码包括: BT_STATUS_SUCCESS = 0, // 成功 BT_STATUS_FAIL = 1, // 失败 BT_STATUS_NOT_READY = 2, // 未就绪 ... 等等 因此,我们可以这样解释: </think> ### `BT_STATUS_SUCCESS` 含义解析 **`BT_STATUS_SUCCESS` 是蓝牙开发中的核心状态码,表示蓝牙操作已成功完成**。它在蓝牙协议栈中作为标准返回值使用,主要出现在以下场景: 1. **API调用返回值** 当蓝牙栈的函数(如建立连接、发送数据、启动服务等)正确执行时返回该状态码: ```c bt_status_t status = btif_gattc_discover_services(conn_id); if (status == BT_STATUS_SUCCESS) { // 服务发现成功后的处理逻辑 } ``` 此时 `status=0` (即`BT_STATUS_SUCCESS`) 表示操作成功[^1]。 2. **事件回调参数** 在异步操作完成时,通过回调函数传递成功状态: ```c void btm_sec_cb(BT_EVENT event, bt_status_t status) { if (status == BT_STATUS_SUCCESS) { // 安全认证成功处理 } } ``` 3. **状态机流转标志** 在状态机(如 `btm_sec_cb.pairing_state`)中驱动状态转移: ```mermaid stateDiagram-v2 WAIT_AUTHENTICATION --> IDLE : BT_STATUS_SUCCESS WAIT_AUTHENTICATION --> ERROR : BT_STATUS_FAIL ``` --- #### 技术特性 | 特性 | 说明 | |------|------| | **数值定义** | 通常定义为 `0` (`#define BT_STATUS_SUCCESS 0`) | | **二进制兼容** | 跨蓝牙版本保持数值不变(如 BT4.2/BT5.x) | | **错误处理** | 需与`BT_STATUS_FAIL`(非0值)对比使用 | | **内存管理** | 成功时需手动释放关联资源(如 `osi_free()`) | --- #### 典型错误场景分析 当操作失败时,需排查以下维度: 1. **协议栈状态** 检查蓝牙控制器是否初始化完成(`BTM_DEV_STATE_UP`) 2. **参数有效性** 验证传入参数(如设备地址格式 `bd_addr_t`) 3. **资源限制** 确认内存/连接数未达上限(如 `MAX_L2CAP_LINKS`) 4. **权限配置** 检查 AndroidManifest.xml 的蓝牙权限声明[^2] --- ### 相关问题 1. `BT_STATUS_SUCCESS` 与操作系统错误码(如 Linux `errno`)如何映射? 2. 蓝牙服务(GATT Server)启动返回 `BT_STATUS_SUCCESS` 是否代表客户端可立即连接? 3. 在异步操作中,`BT_STATUS_SUCCESS` 是否保证回调函数一定会被执行? 4. 如何通过 ADB 日志过滤出所有返回 `BT_STATUS_SUCCESS` 的蓝牙操作? 5. 蓝牙配对过程中哪些关键节点必须检测 `BT_STATUS_SUCCESS`? [^1]: 蓝牙核心规范状态码定义 [^2]: Android 蓝牙权限配置文档
阅读全文

相关推荐

static void btif_dm_cb_create_bond(const RawAddress bd_addr, 760 tBT_TRANSPORT transport) { 761 bool is_hid = check_cod(&bd_addr, COD_HID_POINTING); 762 bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING); 763 764 if (transport == BT_TRANSPORT_AUTO && is_device_le_audio_capable(bd_addr)) { 765 LOG_INFO("LE Audio capable, forcing LE transport for Bonding"); 766 transport = BT_TRANSPORT_LE; 767 } 768 769 int device_type = 0; 770 tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC; 771 std::string addrstr = bd_addr.ToString(); 772 const char* bdstr = addrstr.c_str(); 773 if (transport == BT_TRANSPORT_LE) { 774 if (!btif_config_get_int(bdstr, "DevType", &device_type)) { 775 btif_config_set_int(bdstr, "DevType", BT_DEVICE_TYPE_BLE); 776 } 777 if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) != 778 BT_STATUS_SUCCESS) { 779 // Try to read address type. OOB pairing might have set it earlier, but 780 // didn't store it, it defaults to BLE_ADDR_PUBLIC 781 uint8_t tmp_dev_type; 782 tBLE_ADDR_TYPE tmp_addr_type = BLE_ADDR_PUBLIC; 783 BTM_ReadDevInfo(bd_addr, &tmp_dev_type, &tmp_addr_type); 784 addr_type = tmp_addr_type; 785 786 btif_storage_set_remote_addr_type(&bd_addr, addr_type); 787 } 788 } 789 if ((btif_config_get_int(bdstr, "DevType", &device_type) && 790 (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) == 791 BT_STATUS_SUCCESS) && 792 (device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) || 793 (transport == BT_TRANSPORT_LE)) { 794 BTA_DmAddBleDevice(bd_addr, addr_type, 795 static_cast<tBT_DEVICE_TYPE>(device_type)); 796 } 797 798 if (is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) { 799 const bt_status_t status = 800 GetInterfaceToProfiles()->profileSpecific_HACK->btif_hh_connect( 801 &bd_addr); 802 if (status != BT_STATUS_SUCCESS) 803 bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE); 804 } else { 805 BTA_DmBond(bd_addr, addr_type, transport, device_type); 806 } 807 /* Track originator of bond creation */ 808 pairing_cb.is_local_initiated = true; 这段代码的意思是

static void btif_dm_cb_create_bond(const RawAddress bd_addr, 760 tBT_TRANSPORT transport) { 761 bool is_hid = check_cod(&bd_addr, COD_HID_POINTING); 762 bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING); 763 764 if (transport == BT_TRANSPORT_AUTO && is_device_le_audio_capable(bd_addr)) { 765 LOG_INFO("LE Audio capable, forcing LE transport for Bonding"); 766 transport = BT_TRANSPORT_LE; 767 } 768 769 int device_type = 0; 770 tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC; 771 std::string addrstr = bd_addr.ToString(); 772 const char* bdstr = addrstr.c_str(); 773 if (transport == BT_TRANSPORT_LE) { 774 if (!btif_config_get_int(bdstr, "DevType", &device_type)) { 775 btif_config_set_int(bdstr, "DevType", BT_DEVICE_TYPE_BLE); 776 } 777 if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) != 778 BT_STATUS_SUCCESS) { 779 // Try to read address type. OOB pairing might have set it earlier, but 780 // didn't store it, it defaults to BLE_ADDR_PUBLIC 781 uint8_t tmp_dev_type; 782 tBLE_ADDR_TYPE tmp_addr_type = BLE_ADDR_PUBLIC; 783 BTM_ReadDevInfo(bd_addr, &tmp_dev_type, &tmp_addr_type); 784 addr_type = tmp_addr_type; 785 786 btif_storage_set_remote_addr_type(&bd_addr, addr_type); 787 } 788 } 789 if ((btif_config_get_int(bdstr, "DevType", &device_type) && 790 (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) == 791 BT_STATUS_SUCCESS) && 792 (device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) || 793 (transport == BT_TRANSPORT_LE)) { 794 BTA_DmAddBleDevice(bd_addr, addr_type, 795 static_cast<tBT_DEVICE_TYPE>(device_type)); 796 } 797 798 if (is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) { 799 const bt_status_t status = 800 GetInterfaceToProfiles()->profileSpecific_HACK->btif_hh_connect( 801 &bd_addr); 802 if (status != BT_STATUS_SUCCESS) 803 bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE); 804 } else { 805 BTA_DmBond(bd_addr, addr_type, transport, device_type); 806 } 807 /* Track originator of bond creation */ 808 pairing_cb.is_local_initiated = true; 809 } 分析一下这段代码的作用

#include <stdint.h> #include <stddef.h> #include <string.h> #include <assert.h> #include <stdio.h> #include "btdm_host.h" #include "btdm_utils.h" #include "pan_api.h" #include "fdb_app.h" #include "app_config.h" #include "app_bt.h" #include "user_bt.h" #include "ethernetif.h" #include "FreeRTOS.h" #ifndef LOG_ENABLE #define LOG_ENABLE #endif #include "co_log.h" #ifdef LOG_LOCAL_LEVEL #undef LOG_LOCAL_LEVEL #endif #define LOG_LOCAL_LEVEL LOG_LEVEL_INFO #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) > (b) ? (b) : (a)) const BtAccessModeInfo access_mode_nc = { .inqInterval = 0x800, .inqWindow = 0x12, .pageInterval = 0x800, .pageWindow = 0x12, }; static BtHandler securityHandler; static BtHandler globalHandler; static BtSecurityParms secParms; static char hf_codec[2]; uint8_t default_name[] = "FR30xx_0000"; //HfChannel hf_channel[NUM_BT_DEVICES]; //HfgChannel hfg_channel[NUM_BT_DEVICES]; //A2dpStream Stream[NUM_STREAMS]; //AvrcpChannel rcpCtChannel[NUM_BT_DEVICES]; //AvrcpChannel rcpTgChannel[NUM_BT_DEVICES]; HfChannel *hf_channel; HfgChannel *hfg_channel; A2dpStream *Stream; AvrcpChannel *rcpCtChannel; AvrcpChannel *rcpTgChannel; //BtPacket *scoPacket; uint8_t SbcSnkElements[]={ A2DP_SBC_CODEC_INF_ELEMENT( /* 48000 and 44100 are required for SNK */ A2DP_SBC_CODEC_FREQ_48000 | A2DP_SBC_CODEC_FREQ_44100 | A2DP_SBC_CODEC_FREQ_32000 | A2DP_SBC_CODEC_FREQ_16000, /* All modes required for SNK */ A2DP_SBC_CODEC_CHNL_MODE_MONO | A2DP_SBC_CODEC_CHNL_MODE_DUAL | A2DP_SBC_CODEC_CHNL_MODE_STEREO | A2DP_SBC_CODEC_CHNL_MODE_JOINT, /* One block size must be supported */ A2DP_SBC_CODEC_BLOCKS_16 | A2DP_SBC_CODEC_BLOCKS_12 | A2DP_SBC_CODEC_BLOCKS_8 | A2DP_SBC_CODEC_BLOCKS_4, /* Both 8 and 4 must be supported */ A2DP_SBC_CODEC_SUBBANDS_8 | A2DP_SBC_CODEC_SUBBANDS_4, /* Both allocation methods must be supported in SNK */ A2DP_SBC_CODEC_ALLOCATION_LOUDNESS | A2DP_SBC_CODEC_ALLOCATION_SNR, /* Minium bitpool */ 2, /* Maximum bitpool */ 53) }; uint8_t AacSnkElements[] = { A2DP_AAC_CODEC_MPEG2_LC | A2DP_AAC_CODEC_MPEG4_LC, A2DP_AAC_CODEC_FREQ_44100, A2DP_AAC_CODEC_FREQ_48000 | A2DP_AAC_CODEC_CHNL_MONO | A2DP_AAC_CODEC_CHNL_STEREO, A2DP_AAC_CODEC_VBR, 0x00, 0x00 }; /* Source SBC Elements */ static uint8_t SbcSrcElements[] = { A2DP_SBC_CODEC_INF_ELEMENT(/* 48000 or 44100 is required for SRC */ /*A2DP_SBC_CODEC_FREQ_48000 | */ A2DP_SBC_CODEC_FREQ_44100 /*| A2DP_SBC_CODEC_FREQ_32000 | A2DP_SBC_CODEC_FREQ_16000*/, /* MONO and one other required for SRC */ A2DP_SBC_CODEC_CHNL_MODE_MONO | A2DP_SBC_CODEC_CHNL_MODE_DUAL | A2DP_SBC_CODEC_CHNL_MODE_STEREO | A2DP_SBC_CODEC_CHNL_MODE_JOINT, /* One block size must be supported */ A2DP_SBC_CODEC_BLOCKS_16 | A2DP_SBC_CODEC_BLOCKS_12 | A2DP_SBC_CODEC_BLOCKS_8 | A2DP_SBC_CODEC_BLOCKS_4, /* SRC must support 8 subbands */ A2DP_SBC_CODEC_SUBBANDS_8 | A2DP_SBC_CODEC_SUBBANDS_4, /* SRC must support LOUDNESS */ A2DP_SBC_CODEC_ALLOCATION_LOUDNESS | A2DP_SBC_CODEC_ALLOCATION_SNR, /* Minium bitpool */ 2, /* Maximum bitpool */ 53) }; AvdtpCodec sbcSnkCodec1; //local codec information AvdtpCodec aacSnkCodec1; AvdtpCodec sbcSnkCodec2; //local codec information AvdtpCodec aacSnkCodec2; AvdtpCodec sbcSrcCodec1; AvdtpCodec sbcSrcCodec2; static AvdtpCodec cfgCodec; static uint8_t cfgElements[4]; BtRemoteDevice *last_rem_dev = NULL; extern void CMGR_SetAudioVoiceSettings(BtScoAudioSettings settings); MeCommandToken *name_token; static void name_result_handler(const BtEvent *event) { printf("name result: %d,%d\r\n",event->eType,event->errCode); if((event->eType != BTEVENT_NAME_RESULT) || (event->p.meToken != name_token)){ return; } if(event->errCode == 0){ printf("$$$$$addr:%x,%x,name:%d,%s\r\n",event->p.meToken->p.name.bdAddr.A[0],event->p.meToken->p.name.bdAddr.A[1],event->p.meToken->p.name.io.out.len,event->p.meToken->p.name.io.out.name); } if(name_token){ btdm_free(name_token); name_token = 0; } } void bt_name_query(BD_ADDR *addr, BtPageScanInfo *psi) { BtStatus status; ///doing name request if(name_token){ return; } name_token = (MeCommandToken *)btdm_malloc(sizeof(MeCommandToken)); memcpy(&name_token->p.name.bdAddr,addr,6); memcpy(&name_token->p.name.io.in.psi,psi,sizeof(BtPageScanInfo)); //memset(&name_token.p.name.io.in.psi,0,sizeof(BtPageScanInfo)); name_token->callback = name_result_handler; status = ME_GetRemoteDeviceName(name_token); if(status != BT_STATUS_PENDING){ btdm_free(name_token); name_token = 0; } printf("bt_name_query: %x,%x\r\n",addr->A[0],addr->A[1]); } uint8_t bt_get_free_hf_channel(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ if(hf_channel[index].state == HF_STATE_CLOSED){ break; } } return index; } uint8_t bt_get_free_hfg_channel(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ if(hfg_channel[index].state == HFG_STATE_CLOSED){ break; } } return index; } uint8_t bt_get_free_a2dp_sink_stream(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ //if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device->state == A2DP_DEV_STATE_DISCONNECTED)){ if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device == NULL)){ break; } } return index; } uint8_t bt_get_free_a2dp_source_stream(void) { uint8_t index = 0; for(index = 2; index < NUM_STREAMS; index++){ //if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device->state == A2DP_DEV_STATE_DISCONNECTED)){ if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device == NULL)){ break; } } return index; } uint8_t bt_get_free_avrcp_channel(void) { uint8_t index = 0; for(index = 0; index < NUM_BT_DEVICES; index++){ if(rcpCtChannel[index].chnl.conn.state == 0){ break; } } return index; } void bt_avrcp_register_notification(AvrcpChannel *chnl, uint16_t event_mask) { AvrcpAdvancedPdu *avrcp_cmd; BtStatus status; printf("avrcp register event:%x\r\n",event_mask); if(event_mask & AVRCP_ENABLE_PLAY_STATUS_CHANGED){ ///注册播放状态改变事件,当TG播放状态改变时,产生AVRCP_EVENT_ADV_NOTIFY事件 avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_MEDIA_STATUS_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } if(event_mask & AVRCP_ENABLE_TRACK_CHANGED){ ///注册歌曲改变事件,当TG播放状态改变时,产生AVRCP_EVENT_ADV_NOTIFY事件 avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_TRACK_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } if(event_mask & AVRCP_ENABLE_VOLUME_CHANGED){ ///注册歌曲改变事件,当TG播放状态改变时,产生AVRCP_EVENT_ADV_NOTIFY事件 avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_VOLUME_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } } /// 0--- not supported type, 1---cvsd, 2---msbc, 3---cvsd&msbc static uint8_t bt_parse_hf_codec_type(uint8_t *data) { uint8_t ret = 0; uint8_t index,len; len = strlen((void *)data); for(uint8_t i = 0; i < len; i++) { if((data[i] > '9') || (data[i] < '1')){ continue; } if(ret == 0){ if(data[i] == '1'){ ret = 1; } else if(data[i] == '2'){ ret = 2; } else{ ret = 0; break; } } else if(ret == 1){ if(data[i] == '2'){ ret = 3; } else{ ret = 0; break; } } else if(ret == 2){ if(data[i] == '1'){ ret = 3; } else{ ret = 0; break; } } } return ret; } static void security_event_handler(const BtEvent *event) { //BtDeviceContext *bdc; switch(event->eType) { case BTEVENT_PIN_REQ: SEC_SetPin(event->p.remDev, (const uint8_t *)"0000", 4, BPT_SAVE_TRUSTED); break; case BTEVENT_AUTHORIZATION_REQ: SEC_Authorize(event->p.remDev, TRUE, TRUE); break; //case BTEVENT_PAIRING_COMPLETE: // bdc = DS_FindDevice(&event->p.pairingInfo.remDev->bdAddr); // break; default: //co_printf("SecurityEventHandler: event--0x%02x is not implemented.\r\n", event->eType); break; } } static void me_callback(const BtEvent *event) { LOG_INFO(NULL, "me_callback :%d,%d\r\n",event->eType,event->errCode); switch (event->eType) { case BTEVENT_HCI_INITIALIZED: break; case BTEVENT_INQUIRY_CANCELED: //printf("inquiry canceled\r\n"); bt_update_conn_status(BT_INFO_INQ_CANCEL, NULL, NULL); break; case BTEVENT_INQUIRY_RESULT: // { // uint8_t name[MAX_NAME_SIZE]; // uint8_t len; // printf("inq result: %x\r\n",event->p.inqResult.classOfDevice); // printf("addr:0x%02x%02x%02x%02x%02x%02x\r\n",event->p.inqResult.bdAddr.A[0],event->p.inqResult.bdAddr.A[1],event->p.inqResult.bdAddr.A[2], // event->p.inqResult.bdAddr.A[3],event->p.inqResult.bdAddr.A[4],event->p.inqResult.bdAddr.A[5]); // printf("rssi:%d,name: ",event->p.inqResult.rssi); // bt_parse_inq_result((uint8_t *)event->p.inqResult.extInqResp,name,&len); // for(uint8_t i = 0; i < len; i++) // { // printf("%c",name[i]); // } // printf("\r\n"); // } bt_update_conn_status(BT_INFO_INQ_RESULT, NULL, &event->p.inqResult); break; case BTEVENT_INQUIRY_COMPLETE: bt_update_conn_status(BT_INFO_INQ_COMP, NULL, NULL); //ME_Inquiry(BT_IAC_GIAC, 5, 5); break; case BTEVENT_LINK_CONNECT_REQ: ME_AcceptIncomingLink(event->p.remDev, BCR_SLAVE); break; case BTEVENT_LINK_CONNECT_IND: // if(user_bt_env.bt_connect_cb){ // user_bt_env.bt_connect_cb(BTEVENT_LINK_CONNECT_IND, &event->p.remDev->bdAddr, event->errCode); // } last_rem_dev = event->p.remDev; bt_connect_act_cmp(BT_EVENT_CON_IND, event->errCode, event->p.remDev); break; case BTEVENT_LINK_CONNECT_CNF: // if(user_bt_env.bt_connect_cb){ // user_bt_env.bt_connect_cb(BTEVENT_LINK_CONNECT_CNF, &event->p.remDev->bdAddr, event->errCode); // } last_rem_dev = event->p.remDev; bt_connect_act_cmp(BT_EVENT_CON_CNF, event->errCode, event->p.remDev); break; case BTEVENT_LINK_DISCONNECT: // if(user_bt_env.bt_disconnect_cb){ // user_bt_env.bt_disconnect_cb(&event->p.bdAddr, event->errCode); // } bt_connect_act_cmp(BT_EVENT_DISCONNECT, event->errCode, event->p.remDev); break; case BTEVENT_ACCESSIBLE_CHANGE: printf("access state = %d\r\n",event->p.aMode); // if(user_bt_env.bt_access_change_cb){ // user_bt_env.bt_access_change_cb(event->p.aMode); // } bt_connect_act_cmp(BT_EVENT_ACC_CHG, event->p.aMode, NULL); break; case BTEVENT_MODE_CHANGE: if(event->p.modeChange.curMode == 0){ printf("Active Mode.\r\n"); }else{ printf("Sniff Mode.\r\n"); } break; case BTEVENT_ROLE_CHANGE: printf("role = %d\r\n",event->p.roleChange.newRole); break; case BTEVENT_HCI_COMMAND_SENT: break; default: break; } } static void hf_callback(HfChannel *Chan, HfCallbackParms *Info) { // static bool scoPacketSent = true; if ((Info->event != HF_EVENT_AUDIO_DATA) && (Info->event != HF_EVENT_AUDIO_DATA_SENT)) { printf("hf_callback: event = %d.\r\n", Info->event); } switch(Info->event){ case HF_EVENT_GATEWAY_FEATURES: //printf("gw feature: %x\r\n",Info->p.features); if((Info->p.features & HFG_FEATURE_CODEC_NEGOTIATON) && (HF_GetSupportedFeature() & HF_FEATURE_CODEC_NEGOTIATION_CFG)){ CMGR_SetAudioVoiceSettings(0x63); }else{ CMGR_SetAudioVoiceSettings(0x60); } break; case HF_EVENT_SERVICE_CONNECT_REQ: bt_update_conn_status(BT_PROFILE_HF_CONN_REQ, Chan, Info); break; case HF_EVENT_SERVICE_CONNECTED: LOG_INFO(NULL,"hf connected\r\n"); //A2DP_OpenStream(&Stream[0], &Info->p.remDev->bdAddr); bt_update_conn_status(BT_PROFILE_HF_CONN, Chan, Info); break; case HF_EVENT_SERVICE_DISCONNECTED: LOG_INFO(NULL,"hf disconnected %d\r\n",Info->errCode); bt_update_conn_status(BT_PROFILE_HF_DISCONN, Chan, Info); break; case HF_EVENT_CALL_IND: bt_update_conn_status(BT_PROFILE_HF_CALL, Chan, Info); break; case HF_EVENT_CALLSETUP_IND: bt_update_conn_status(BT_PROFILE_HF_CALLSETUP, Chan, Info); break; case HF_EVENT_CALLHELD_IND: break; case HF_EVENT_RING_IND: bt_update_conn_status(BT_PROFILE_HF_RING, Chan, Info); break; case HF_EVENT_CALLER_ID_NOTIFY: break; case HF_EVENT_SPEAKER_VOLUME: bt_update_conn_status(BT_PROFILE_HF_SPK_VOL, Chan, Info); break; case HF_EVENT_CURRENT_CALL_STATE: bt_update_conn_status(BT_PROFILE_HF_CURRENT_CALL, Chan, Info); break; case HF_EVENT_AT_RESULT_DATA: bt_update_conn_status(BT_PROFILE_HF_AT_RESULT, Chan, Info); break; case HF_EVENT_AUDIO_CONNECTED: bt_update_conn_status(BT_PROFILE_HF_AUDIO_CONN, Chan, Info); break; case HF_EVENT_AUDIO_DISCONNECTED: bt_update_conn_status(BT_PROFILE_HF_AUDIO_DISCONN, Chan, Info); break; case HF_EVENT_AUDIO_DATA: bt_update_conn_status(BT_PROFILE_HF_AUDIO_DATA, Chan, Info); break; case HF_EVENT_AUDIO_DATA_SENT: // scoPacketSent = true; btdm_free(Info->p.audioPacket->data); btdm_free(Info->p.audioPacket); break; #if HF_CODEC_NEG == XA_ENABLED case HF_EVENT_CODEC_NEGOTIATION: { HfCommand *cmd; if(Info->p.codecID == 1){ //cvsd CMGR_SetAudioVoiceSettings(0x60); }else if(Info->p.codecID == 2){ //msbc CMGR_SetAudioVoiceSettings(0x63); } BtStatus ret = BT_STATUS_NO_RESOURCES; cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); if(cmd != NULL){ hf_codec[0] = Info->p.codecID + '0'; hf_codec[1] = 0; ret = HF_CodecConnectionSetup((HfChannel *)Chan, hf_codec, cmd); } if(ret != BT_STATUS_PENDING){ btdm_free((void *)cmd); } } break; #endif case HF_EVENT_COMMAND_COMPLETE: btdm_free((uint8_t *)Info->p.command); break; default: break; } } static void hfg_callback(HfgChannel *Chan, HfgCallbackParms *Info) { BtStatus status; HfgResponse *rsp; uint8_t codec_type; if ((Info->hfgEvent != HFG_EVENT_AUDIO_DATA) && (Info->hfgEvent != HFG_EVENT_AUDIO_DATA_SENT)) { LOG_INFO(NULL, "hfg_callback :%d\r\n",Info->hfgEvent); } switch (Info->hfgEvent) { case HFG_EVENT_HANDSFREE_FEATURES: printf("remote hf feature: %x\r\n",Info->p.features); // if(Info->p.features & HF_FEATURE_CODEC_NEGOTIATION){ // CMGR_SetAudioVoiceSettings(0x63); // }else{ // CMGR_SetAudioVoiceSettings(0x60); // } break; case HFG_EVENT_SERVICE_CONNECT_REQ: bt_update_conn_status(BT_PROFILE_HFG_CONN_REQ, Chan, Info); break; case HFG_EVENT_SERVICE_CONNECTED: bt_update_conn_status(BT_PROFILE_HFG_CONN, Chan, Info); break; case HFG_EVENT_SERVICE_DISCONNECTED: bt_update_conn_status(BT_PROFILE_HFG_DISCONN, Chan, Info); break; case HFG_EVENT_AUDIO_CONNECTED: { HfgResponse *rsp; rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); HFG_SetIndicatorValue(Chan, HFG_IND_CALL, TRUE, rsp); bt_update_conn_status(BT_PROFILE_HFG_AUDIO_CONN, Chan, Info); } break; case HFG_EVENT_AUDIO_DISCONNECTED: { HfgResponse *rsp; rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); HFG_SetIndicatorValue(Chan, HFG_IND_CALL, FALSE, rsp); bt_update_conn_status(BT_PROFILE_HFG_AUDIO_DISCONN, Chan, Info); } break; case HFG_EVENT_AT_COMMAND_DATA: for(uint8_t i = 0; i < Info->p.data->dataLen; i++) printf("%c",Info->p.data->rawData[i]); printf("\r\n"); rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); status = HFG_SendOK(Chan,rsp); if(status != BT_STATUS_PENDING){ btdm_free((void *)rsp); } // if(memcmp(Info->p.data->rawData,"AT+IPHONEACCEV=1,1,9",sizeof("AT+IPHONEACCEV=1,1,9")) == 0) // { // status = BT_STATUS_NO_RESOURCES; // rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse)); // if(rsp != NULL){ // status = HFG_CreateCodecConnection(&hfg_channel[0], 1, rsp); // } // if(status != BT_STATUS_PENDING){ // btdm_free((void *)rsp); // } // printf("status = %d\r\n",status); // } break; case HFG_EVENT_SUPPORTED_CODEC: codec_type = bt_parse_hf_codec_type(Info->p.ptr); if(codec_type >= 2){ CMGR_SetAudioVoiceSettings(0x63); }else{ CMGR_SetAudioVoiceSettings(0x60); } break; case HFG_EVENT_AUDIO_DATA: { // if(Info->p.audioData->len == 120){ // fputc('M',NULL); // }else if(Info->p.audioData->len == 60){ // fputc('m',NULL); // } // printf("audio data: "); // for(uint8_t i = 0; i < Info->p.audioData->len; i++) // { // printf("%02x ",Info->p.audioData->data[i]); //} // printf("\r\n"); bt_update_conn_status(BT_PROFILE_HFG_AUDIO_DATA, Chan, Info); } break; case HFG_EVENT_AUDIO_DATA_SENT: //fputc('s',NULL); btdm_free((void *)Info->p.audioPacket->data); btdm_free((void *)Info->p.audioPacket); break; case HFG_EVENT_CODEC_CONNECTION_RSP: codec_type = bt_parse_hf_codec_type(Info->p.ptr); printf("hfg codec connection rsp: %s,type = %d\r\n",Info->p.ptr,codec_type); if(codec_type >= 2){ CMGR_SetAudioVoiceSettings(0x63); }else{ CMGR_SetAudioVoiceSettings(0x60); } HFG_CreateAudioLink(&hfg_channel[0],HFG_AR_LOCAL_USER_ACTION); break; case HFG_EVENT_RESPONSE_COMPLETE: btdm_free((void *)Info->p.response); break; } } static void a2dp_callback(A2dpStream *cbStream, const A2dpCallbackParms *Parms) { AvdtpCodec *codec; uint8_t *elements; uint8_t *reqElements; uint8_t error = A2DP_ERR_NO_ERROR; if((Parms->event != A2DP_EVENT_STREAM_DATA_IND ) && (Parms->event != A2DP_EVENT_STREAM_SBC_PACKET_SENT)) { LOG_INFO(NULL, "a2dp callback event=%d,%x,%x\r\n", Parms->event,Parms->error,Parms->discReason); } switch(Parms->event) { case A2DP_EVENT_STREAM_OPEN_IND: bt_update_conn_status(BT_PROFILE_A2DP_OPEN_IND, cbStream, Parms); if (AVDTP_CODEC_TYPE_SBC == Parms->p.configReq->codec.codecType) { codec = A2DP_GetRegisteredCodec(cbStream); elements = codec->elements; reqElements = Parms->p.configReq->codec.elements; printf("a2dp local codec: %x,%x,%x,%x\r\n",elements[0],elements[1],elements[2],elements[3]); printf("a2dp remote codec: %x,%x,%x,%x\r\n",reqElements[0],reqElements[1],reqElements[2],reqElements[3]); /* Check requested elements with registered elements */ if (!(reqElements[0] & (elements[0] & 0xF0))) { error = A2DP_ERR_NOT_SUPPORTED_SAMP_FREQ; } else if (!(reqElements[0] & (elements[0] & 0x0F))) { error = A2DP_ERR_NOT_SUPPORTED_CHANNEL_MODE; } else if (!(reqElements[1] & (elements[1] & 0x0C))) { error = A2DP_ERR_NOT_SUPPORTED_SUBBANDS; } else if (!(reqElements[1] & (elements[1] & 0x03))) { error = A2DP_ERR_NOT_SUPPORTED_ALLOC_METHOD; } else if (reqElements[2] < elements[2]) { error = A2DP_ERR_NOT_SUPPORTED_MIN_BITPOOL_VALUE; } else if (reqElements[3] > elements[3]) { error = A2DP_ERR_NOT_SUPPORTED_MAX_BITPOOL_VALUE; } // if(error == A2DP_ERR_NO_ERROR){ // // sbcinfo.bitPool = reqElements[3]; // // if(reqElements[0]&0x20){ // sbcinfo.sampleFreq = 2;//44100 // } // else{ // sbcinfo.sampleFreq = 3;//48000 // } // // if(reqElements[1]&0x01){ // sbcinfo.allocMethod = 0;//loudness // } // else{ // sbcinfo.allocMethod = 1;//snr // } // } // codec->freq = (reqElements[0] & 0xF0) >> 5; A2DP_OpenStreamRspWithSinkDelay(cbStream, error, AVDTP_SRV_CAT_MEDIA_CODEC, 0); } else if(AVDTP_CODEC_TYPE_MPEG2_4_AAC== Parms->p.configReq->codec.codecType) { codec = A2DP_GetRegisteredCodec(cbStream); elements = codec->elements; reqElements = Parms->p.configReq->codec.elements; // if(reqElements[1] & 0x01) { // codec->freq = 1; // } // else if(reqElements[2] & 0x80) { // codec->freq = 0; // } A2DP_OpenStreamRspWithSinkDelay(cbStream, error, AVDTP_SRV_CAT_MEDIA_CODEC, 0); } else { /* Refuse to accept incoming con to MP3 stream for now */ A2DP_OpenStreamRspWithSinkDelay(cbStream, AVRCP_ERR_UNKNOWN_ERROR, AVDTP_SRV_CAT_MEDIA_CODEC, 0); } break; case A2DP_EVENT_CODEC_INFO: printf("codec info: %x,%x,%x,%x\r\n",Parms->p.codec->elements[0],Parms->p.codec->elements[1],Parms->p.codec->elements[2],Parms->p.codec->elements[3]); /* Found a matching codec */ codec = A2DP_GetRegisteredCodec(cbStream); elements = codec->elements; /* Save the remote codec information. Selection * of capabilities will be made from the UI. */ cfgCodec.codecType = Parms->p.codec->codecType; cfgCodec.elemLen = Parms->p.codec->elemLen; cfgCodec.elements = cfgElements; if (cfgCodec.codecType == AVDTP_CODEC_TYPE_SBC) { /* Only the matching codec information * elements can be selected. */ cfgCodec.elements[0] = (uint8_t)(Parms->p.codec->elements[0] & elements[0]); cfgCodec.elements[1] = (uint8_t)(Parms->p.codec->elements[1] & elements[1]); cfgCodec.elements[2] = (uint8_t)(max(Parms->p.codec->elements[2], elements[2])); cfgCodec.elements[3] = (uint8_t)(min(Parms->p.codec->elements[3], elements[3])); } break; case A2DP_EVENT_GET_CONFIG_IND: LOG_INFO(NULL, "codec type=%d,%x,%x,%x,%x\r\n",cfgCodec.codecType,cfgCodec.elements[0],cfgCodec.elements[1],cfgCodec.elements[2],cfgCodec.elements[3]); /* Make sure something valid is configured for each field */ if (cfgCodec.codecType == AVDTP_CODEC_TYPE_SBC) { if ( (cfgCodec.elements[0] & 0xF0) && (cfgCodec.elements[0] & 0x0F) && (cfgCodec.elements[1] & 0xF0) && (cfgCodec.elements[1] & 0x0C) && (cfgCodec.elements[1] & 0x03)) { /* Pick the sampling rate supported */ if (cfgCodec.elements[0] & 0x80) { cfgCodec.elements[0] &= 0x8F; } else if (cfgCodec.elements[0] & 0x40) { cfgCodec.elements[0] &= 0x4F; } else if (cfgCodec.elements[0] & 0x20) { cfgCodec.elements[0] &= 0x2F; } else if (cfgCodec.elements[0] & 0x10) { cfgCodec.elements[0] &= 0x1F; } /* Pick the channel mode */ if (cfgCodec.elements[0] & 0x01) { cfgCodec.elements[0] &= 0xF1; } else if (cfgCodec.elements[0] & 0x02) { cfgCodec.elements[0] &= 0xF2; } else if (cfgCodec.elements[0] & 0x04) { cfgCodec.elements[0] &= 0xF4; } else if (cfgCodec.elements[0] & 0x08) { cfgCodec.elements[0] &= 0xF8; } /* Pick the block length */ // if (cfgCodec.elements[1] & 0x80) { // cfgCodec.elements[1] &= 0x8F; // } else if (cfgCodec.elements[1] & 0x40) { // cfgCodec.elements[1] &= 0x4F; // } else if (cfgCodec.elements[1] & 0x20) { // cfgCodec.elements[1] &= 0x2F; // } else if (cfgCodec.elements[1] & 0x10) { // cfgCodec.elements[1] &= 0x1F; // } cfgCodec.elements[1] &= 0x1F; /* Pick the number of subbands */ if (cfgCodec.elements[1] & 0x04) { cfgCodec.elements[1] &= 0xF7; } else if (cfgCodec.elements[1] & 0x08) { cfgCodec.elements[1] &= 0xFB; } /* Pick the allocation method */ if (cfgCodec.elements[1] & 0x01) { cfgCodec.elements[1] &= 0xFD; } else if (cfgCodec.elements[1] & 0x02) { cfgCodec.elements[1] &= 0xFE; } /* Select Min/Max Bitpools */ cfgCodec.elements[2] = cfgCodec.elements[2]; cfgCodec.elements[3] = cfgCodec.elements[3]; // /* copy codec info to local*/ // sbcinfo.bitPool = cfgCodec.elements[3]; // // if(cfgCodec.elements[0]&0x20){ // sbcinfo.sampleFreq = 2;//44100 // } // else{ // sbcinfo.sampleFreq = 3;//48000 // } // // if(cfgCodec.elements[1]&0x01){ // sbcinfo.allocMethod = 0;//loudness // } // else{ // sbcinfo.allocMethod = 1;//snr // } A2DP_SetStreamConfigWithSinkDelay(cbStream, &cfgCodec, 0, 0); } else{ A2DP_CloseStream(cbStream); } } break; case A2DP_EVENT_STREAM_OPEN: LOG_INFO(NULL,"a2dp connected\r\n"); bt_update_conn_status(BT_PROFILE_A2DP_CONN, cbStream, Parms); break; case A2DP_EVENT_STREAM_START_IND: A2DP_StartStreamRsp(cbStream, A2DP_ERR_NO_ERROR); break; case A2DP_EVENT_STREAM_STARTED: bt_update_conn_status(BT_PROFILE_A2DP_PLAYING, cbStream, Parms); break; case A2DP_EVENT_STREAM_SUSPENDED: bt_update_conn_status(BT_PROFILE_A2DP_SUSPEND, cbStream, Parms); break; case A2DP_EVENT_STREAM_CLOSED: bt_update_conn_status(BT_PROFILE_A2DP_DISCONN, cbStream, Parms); break; case A2DP_EVENT_STREAM_DATA_IND: bt_update_conn_status(BT_PROFILE_A2DP_STREAM_DATA, cbStream, Parms); break; case A2DP_EVENT_STREAM_SBC_PACKET_SENT: bt_update_conn_status(BT_PROFILE_A2DP_SBC_PKT_SENT, cbStream, Parms); break; default: break; } } static void avrcp_callback(AvrcpChannel *chnl, const AvrcpCallbackParms *Parms) { AvrcpAdvancedPdu *avrcp_cmd; BtStatus status; LOG_INFO(NULL, "avrcp callback event=%d, status=%d, chnl=%x\r\n",Parms->event, Parms->status, chnl); switch (Parms->event) { case AVRCP_EVENT_CONNECT_IND: AVRCP_ConnectRsp(chnl,TRUE); break; case AVRCP_EVENT_CONNECT: { avrcp_cmd = btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtGetCapabilities((AvrcpChannel *)chnl, avrcp_cmd, AVRCP_CAPABILITY_EVENTS_SUPPORTED); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } AVRCP_TgSetEventMask(chnl,AVRCP_ENABLE_VOLUME_CHANGED); } LOG_INFO(NULL, "avrcp connected\r\n"); bt_update_conn_status(BT_PROFILE_AVRCP_CONN, chnl, Parms); break; case AVRCP_EVENT_DISCONNECT: LOG_INFO(NULL, "avrcp disconnected\r\n"); bt_update_conn_status(BT_PROFILE_AVRCP_DISCONN, chnl, Parms); break; case AVRCP_EVENT_ADV_INFO: if(Parms->advOp == AVRCP_OP_SET_ABSOLUTE_VOLUME) { //LOG_INFO("SET_ABSOLUTE_VOLUME is %d.\r\n", event->param.adv.info.volume); printf("+VOL:%02x\r\n",Parms->p.adv.info.volume); } break; case AVRCP_EVENT_ADV_RESPONSE: ///本地查询TG支持事件,返回消�? /**/ if((Parms->advOp == AVRCP_OP_GET_CAPABILITIES) &&(Parms->p.adv.rsp.capability.type == AVRCP_CAPABILITY_EVENTS_SUPPORTED)){ //printf("cap eventmaskk = %x\r\n",event->param.adv.rsp.capability.info.eventMask); uint16_t event_mask = Parms->p.adv.rsp.capability.info.eventMask; bt_update_conn_status(BT_PROFILE_AVRCP_EVENT_SUPPORT, chnl, &event_mask); } ///本地注册事件,返回的当前状�? if(Parms->advOp == AVRCP_OP_REGISTER_NOTIFY) { ///播放状态改变通知的当前状�? if(Parms->p.adv.notify.event == AVRCP_EID_MEDIA_STATUS_CHANGED) { } else if(Parms->p.adv.notify.event == AVRCP_EID_TRACK_CHANGED){ //user_bt_get_media_info(); } } if(Parms->advOp == AVRCP_OP_GET_MEDIA_INFO){ uint16_t len0 = Parms->p.adv.rsp.element.txt[0].length; uint16_t len1 = Parms->p.adv.rsp.element.txt[1].length; printf("media info: %d,%s,%d\r\n",len0,Parms->p.adv.rsp.element.txt[0].string,len1); } if(Parms->advOp == AVRCP_OP_GET_PLAY_STATUS){ printf("media length:%d,pos:%d,status:%d\r\n",Parms->p.adv.rsp.playStatus.length,Parms->p.adv.rsp.playStatus.position,Parms->p.adv.rsp.playStatus.mediaStatus); } break; case AVRCP_EVENT_PANEL_CNF: if(Parms->p.panelCnf.press == TRUE){ switch(Parms->p.panelCnf.operation) { case AVRCP_POP_PAUSE: AVRCP_SetPanelKey(chnl, AVRCP_POP_PAUSE, FALSE); break; case AVRCP_POP_PLAY: AVRCP_SetPanelKey(chnl, AVRCP_POP_PLAY, FALSE); break; case AVRCP_POP_FORWARD: AVRCP_SetPanelKey(chnl, AVRCP_POP_FORWARD, FALSE); break; case AVRCP_POP_BACKWARD: AVRCP_SetPanelKey(chnl, AVRCP_POP_BACKWARD, FALSE); break; case AVRCP_POP_STOP: AVRCP_SetPanelKey(chnl, AVRCP_POP_STOP, FALSE); break; } } break; case AVRCP_EVENT_ADV_NOTIFY: { const AvrcpAdvNotifyParms *avrcp_ntf = &Parms->p.adv.notify; if(Parms->errorCode == AVRCP_ERR_NO_ERROR) { switch(avrcp_ntf->event) { case AVRCP_EID_TRACK_CHANGED: { avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_TRACK_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } break; case AVRCP_EID_MEDIA_STATUS_CHANGED: { ///重新注册播放状态改变通知消息 uint8_t media_status = Parms->p.adv.notify.p.mediaStatus; bt_update_conn_status(BT_PROFILE_AVRCP_MEDIA_STATUS, chnl, &media_status); avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); avrcp_cmd->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_MEDIA_STATUS_CHANGED, 0); if (status != BT_STATUS_PENDING) { btdm_free(avrcp_cmd->parms); btdm_free(avrcp_cmd); } } break; } } } break; case AVRCP_EVENT_ADV_TX_DONE: btdm_free(Parms->p.adv.txPdu->parms); btdm_free(Parms->p.adv.txPdu); break; default: break; } } static void pbap_callback(PbapClientCallbackParms *Parms) { printf("pbap callback event = %d\r\n",Parms->event); switch (Parms->event) { case PBAP_EVENT_PARAMS_RX: { if ((Parms->oper == PBAPOP_PULL_PHONEBOOK) || (Parms->oper == PBAPOP_PULL_VCARD_LISTING)) { printf("miss calls: %d,pb size=%d\r\n",Parms->u.paramsRx.newMissedCalls,Parms->u.paramsRx.phonebookSize); } } break; case PBAP_EVENT_DATA_IND: bt_update_conn_status(BT_PROFILE_PBAP_DATA_IND, NULL, Parms); break; case PBAP_EVENT_TP_CONNECTED: bt_update_conn_status(BT_PROFILE_PBAP_CONN, NULL, Parms); break; case PBAP_EVENT_TP_DISCONNECTED: bt_update_conn_status(BT_PROFILE_PBAP_DISCONN, NULL, Parms); break; case PBAP_EVENT_CONTINUE: /* Always call continue to keep the commands flowing */ PBAP_ClientContinue(Parms->client); break; case PBAP_EVENT_ABORTED: /* The requested operation was aborted. */ break; case PBAP_EVENT_COMPLETE: bt_update_conn_status(BT_PROFILE_PBAP_COMP, NULL, Parms); break; default: break; } } #if BTDM_STACK_ENABLE_PAN static void HandleFilters(PanUser *pan, uint16_t *range, uint16_t numRanges) { BtStatus status; uint8_t i; PanControlRespPkt *controlRespPkt; LOG_INFO(NULL, "Pan: Rx'd BNEP_CONTROL:NET_TYPE_SET %d Filter ranges\r\n", numRanges); for (i = 0; i < numRanges*2; i+=2) { LOG_INFO(NULL, " ==>Range start: %#.4x\r\n", BEtoHost16((uint8_t *)&range[i])); LOG_INFO(NULL, " ==>Range end: %#.4x\r\n", BEtoHost16((uint8_t *)&range[i+1])); } controlRespPkt = pvPortMalloc(sizeof(PanControlRespPkt)); if (controlRespPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources\r\n"); return; } /* Set the response message */ StoreBE16(controlRespPkt->message, BNEP_FR_OPERATION_SUCCESS); /* Send the Control Response packet */ status = PAN_ControlResponse(pan, BNEP_FILTER_NET_TYPE_RESPONSE_MSG, controlRespPkt); LOG_INFO(NULL, "PanApp: PAN_ControlResponse() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { vPortFree(controlRespPkt); } } static void HandleAddrs(PanUser *pan, BNEP_ADDR *addr, uint16_t numRanges) { BtStatus status; uint8_t i; PanControlRespPkt *controlRespPkt; uint8_t buffer[40]; LOG_INFO(NULL, "Pan: Rx'd BNEP_CONTROL:MULTI_ADDR_SET %d Address ranges\r\n", numRanges); for (i = 0; i < numRanges*2; i+=2) { bnep_addr_ntoa((BNEP_ADDR *)(&addr[i]), (char *)buffer); LOG_INFO(NULL, " ==>Address start: %s\r\n", buffer); bnep_addr_ntoa((BNEP_ADDR *)(&addr[i+1]), (char *)buffer); LOG_INFO(NULL, " ==>Address end: %s\r\n", buffer); } controlRespPkt = pvPortMalloc(sizeof(PanControlRespPkt)); if (controlRespPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources\r\n"); return; } /* Set the response message */ StoreBE16(controlRespPkt->message, BNEP_FR_OPERATION_SUCCESS); /* Send the Control Response packet */ status = PAN_ControlResponse(pan, BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG, controlRespPkt); LOG_INFO(NULL, "PanApp: PAN_ControlResponse() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { vPortFree(controlRespPkt); } } /* --------------------------------------------------------------------------- * PAN PANU Packet handler * --------------------------------------------------------------------------- */ static void HandlePanuPacket(PanCallbackParms *Info) { bool DisplayUnknownPackets = true; uint16_t bodyLen, ipLen, ipTotLen; BtStatus status; ArpHeader *arpHdrIn; IpHeader *ipHdr; UdpHeader *udpHdr; DhcpHeader *dhcpHdr; IcmpHeader *icmpHdr; PanPacket *panPkt = 0; BNEP_ADDR *macAddr = 0; uint8_t buff[1024]; uint32_t myIpAddr, dstIP; PanPacketType panPktType; switch (Info->type) { case PANPKT_ARP_REQUEST: LOG_INFO(NULL, "Received ARP Request\r\n"); arpHdrIn = (ArpHeader *)(Info->pkt + ETHER_HDR_SIZE); /* The reply is already set up. Just forward it. */ PAN_ForwardPkt(Info->pan, Info->pkt, Info->rxPktLen); break; case PANPKT_ARP_REPLY: LOG_INFO(NULL, "Received ARP Reply\r\n"); arpHdrIn = (ArpHeader *)Info->pkt; myIpAddr = PAN_GetLocalIpAddr_v2(); if (myIpAddr == BEtoHost32((uint8_t *)&arpHdrIn->dstIP) && PAN_GetRemoteIpAddr_v2(Info->pan) == BEtoHost32((uint8_t *)&arpHdrIn->srcIP)) { /* This is a response to my arp request */ PAN_SetRemoteMacAddr(Info->pan, arpHdrIn->srcMac); LOG_INFO(NULL, "Destination MAC address = %02x:%02x:%02x:%02x:%02x:%02x\r\n", arpHdrIn->srcMac[0], arpHdrIn->srcMac[1], arpHdrIn->srcMac[2], arpHdrIn->srcMac[3], arpHdrIn->srcMac[4], arpHdrIn->srcMac[5]); } break; case PANPKT_IP: if (DisplayUnknownPackets == true) { LOG_INFO(NULL, "Received IPv4 Packet\r\n"); // SOCKADDR_IN from; // ipHdr = (IpHeader *)Info->pkt; // memset((uint8_t*)&from, 0, sizeof(from)); // from.sin_addr.S_un.S_addr = ipHdr->srcIP; // from.sin_family = AF_INET; // from.sin_port = 0; // LOG_INFO(NULL, "Remote IP address: %s, protocol: %d, Length: %d\r\n", // inet_ntoa(from.sin_addr), ipHdr->proto, ipHdr->totalLen); } break; case PANPKT_TCP: if (DisplayUnknownPackets == true) { LOG_INFO(NULL, "Received TCP Packet\r\n"); ipHdr = (IpHeader *)Info->pkt; } break; case PANPKT_UDP: if (DisplayUnknownPackets == true) { LOG_INFO(NULL, "Received UDP Packet\r\n"); ipHdr = (IpHeader *)Info->pkt; udpHdr = (UdpHeader *)((uint8_t *)ipHdr + sizeof(IpHeader)); } break; case PANPKT_DHCP_REQUEST: LOG_INFO(NULL, "Received DHCP Request Packet\r\n"); LOG_INFO(NULL, " Not valid for a PANU!\r\n"); break; case PANPKT_DHCP_REPLY: /* This is for me */ { LOG_INFO(NULL, "Received my DHCP Reply Packet\r\n"); // SOCKADDR_IN sAddr = {AF_INET, 0, 0, 0}; // dhcpHdr = (DhcpHeader *)(Info->pkt + sizeof(IpHeader) + sizeof(UdpHeader)); // if (dhcpHdr->options[2] == DHCPOFFER) { // sAddr.sin_addr.S_un.S_addr = dhcpHdr->yiaddr; // LOG_INFO(NULL, "DHCP server offered IP address %s\r\n", inet_ntoa(sAddr.sin_addr)); // /* Set the device addresses used to make the DHCPREQUEST packet */ // PAN_SetLocalIpAddr_v2(BEtoHost32((uint8_t *)&dhcpHdr->yiaddr)); // PAN_SetDhcpAddr_v2(BEtoHost32((uint8_t *)&dhcpHdr->siaddr)); // bodyLen = MakeDhcpPacket(INADDR_BROADCAST, &panPkt, BOOTP_CLIENT, DHCPREQUEST); // status = PAN_SendPkt(Info->pan, panPkt, PANPKT_DHCP_REQUEST, bodyLen); // LOG_INFO(NULL, "PanApp: PAN_SendPkt() Returned 0x%04x\r\n", status); // } // else if (dhcpHdr->options[2] == DHCPACK) { // sAddr.sin_addr.S_un.S_addr = dhcpHdr->yiaddr; // LOG_INFO(NULL, "DHCP server ACK'd IP address %s\r\n", inet_ntoa(sAddr.sin_addr)); // } } break; case PANPKT_ETHER_PKT: PAN_ForwardPkt(Info->pan, Info->pkt, Info->rxPktLen); break; default: LOG_INFO(NULL, "PanApp: Rx'd unrecognized packet type %d\r\n", Info->type); break; } } void pan_callback(PanCallbackParms *Params) { BtStatus status; PanPacket *panPkt = 0; ArpHeader *arpHdr; uint16_t bodyLen; PanSetupConnPkt *setupPkt; PanControlRespPkt *setupRespPkt; uint16_t numRanges; PanPacketType panPktType; switch (Params->event) { case PANEVENT_OPEN: LOG_INFO(NULL, "PanApp: Received PANEVENT_OPEN event\r\n"); #if 1 BD_ADDR addr; BNEP_ADDR addr_local, addr_remote; ME_ReadLocalBdAddr(&addr); memcpy(&addr_local.addr[0], &addr.A[0], BNEP_ADDR_SIZE); addr_remote = Params->pan->bnepPanu.bnepAddr; /* notify LWIP data link layer is established */ bnep_lwip_netif_up(Params->pan, &addr_local, &addr_remote); #else /* ARP to verify my Link Local address */ panPktType = PANPKT_ARP_REQUEST; bodyLen = sizeof(ArpHeader); panPkt = pvPortMalloc(sizeof(PanPacket) + bodyLen); arpHdr = (ArpHeader *)panPkt->body; /* Set the target address to my initial Link Local address */ PAN_MakeArpHdr(arpHdr, PAN_GetLocalIpAddr_v2()); status = PAN_SendPkt(Params->pan, panPkt, panPktType, bodyLen); if (status != BT_STATUS_PENDING) { LOG_INFO(NULL, "PanApp: Send failed\r\n"); vPortFree(panPkt); return; } LOG_INFO(NULL, "PanApp: Sent ARP to validate Link Local Address\r\n"); #endif break; case PANEVENT_SETUP_CONNECTION: LOG_INFO(NULL, "PanApp: Received PANEVENT_SETUP_CONNECTION event\r\n"); /* Complete the open with a Setup Connection Request */ setupPkt = pvPortMalloc(sizeof(PanSetupConnPkt)); if (setupPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources"); return; } status = PAN_SetupConnection(Params->pan, setupPkt); LOG_INFO(NULL, "PanApp: PAN_SetupConnection() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { vPortFree(setupPkt); } break; case PANEVENT_SETUP_CONN_REQ: LOG_INFO(NULL, "PanApp: Received PANEVENT_SETUP_CONN_REQ event\r\n"); /* Complete the open with a Setup Connection Response */ setupRespPkt = pvPortMalloc(sizeof(PanControlRespPkt)); if (setupRespPkt == 0) { LOG_INFO(NULL, "PanApp: No Resources\r\n"); return; } /* The setup connection message has already been validated. The * status parameter contains the validation results of type * BnepSetupResponseMsg. Just copy the status into my response * and send it back. */ StoreBE16(setupRespPkt->message, Params->status); status = PAN_ControlResponse(Params->pan, BNEP_SETUP_CONNECTION_RESPONSE_MSG, setupRespPkt); LOG_INFO(NULL, "PanApp: PAN_ControlResponse() Returned 0x%04x\r\n", status); if (status != BT_STATUS_PENDING) { btdm_free(setupRespPkt); } break; case PANEVENT_CONTROL_IND: switch (Params->pkt[1]) { case BNEP_FILTER_NET_TYPE_SET_MSG: numRanges = Params->rxPktLen - BNEP_CONTROL_HDR_SIZE; numRanges /= ETHER_RANGE_SIZE; HandleFilters(Params->pan, (uint16_t *)(Params->pkt + 2), numRanges); break; case BNEP_FILTER_NET_TYPE_RESPONSE_MSG: LOG_INFO(NULL, "PanApp: Received FILTER_NET_TYPE_RESPONSE event\r\n"); break; case BNEP_FILTER_MULTI_ADDR_SET_MSG: numRanges = Params->rxPktLen - BNEP_CONTROL_HDR_SIZE; numRanges /= BNEP_ADDR_SIZE * 2; HandleAddrs(Params->pan, (BNEP_ADDR *)(Params->pkt + 2), numRanges); break; case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG: LOG_INFO(NULL, "PanApp: Received MULTI_ADDR_RESPONSE event\r\n"); break; default: break; } break; case PANEVENT_CLOSED: LOG_INFO(NULL, "PanApp: Received PANEVENT_CLOSED event\r\n"); bnep_lwip_netif_down(); break; case PANEVENT_DATA_IND: LOG_INFO(NULL, "PanApp: Received PANEVENT_DATA_IND event\r\n"); HandlePanuPacket(Params); break; case PANEVENT_DATA_HANDLED: LOG_INFO(NULL, "PanApp: Received PANEVENT_DATA_HANDLED event\r\n"); vPortFree(Params->pkt); break; case PANEVENT_SDP_FAILED: LOG_INFO(NULL, "PanApp: Received PANEVENT_SDP_FAILED event\r\n"); break; default: LOG_INFO(NULL, "PanApp: Received Unknown Event %d with status 0x%04x\r\n", Params->event, Params->status); break; } } #endif //void a2dp_device_callback(void *Device, const void *Parms) //{ // switch(*(volatile uint8_t *)Parms){ // case 1/*AVDEV_EVENT_AVDTP_CONNECT_IND*/: // AVDEV_SignalConnectRsp(Device, TRUE, a2dp_device_callback); // break; // default: // break; // } //} void app_btdm_struct_size_dump(void) { printf("BTDM STRUCT SIZE: defined in stack.\r\n"); extern void btdm_struct_size_dump(void); btdm_struct_size_dump(); printf("BTDM STRUCT SIZE: defined in api.\r\n"); printf("BtEvent is %d\r\n", sizeof(BtEvent)); printf("BtRemoteDevice is %d\r\n", sizeof(BtRemoteDevice)); printf("RfDeferEvent is %d\r\n", sizeof(RfDeferEvent)); printf("RfChannel is %d\r\n", sizeof(RfChannel)); printf("HfChannel is %d\r\n", sizeof(HfChannel)); printf("HfCommand is %d\r\n", sizeof(HfCommand)); printf("HfCallbackParms is %d\r\n", sizeof(HfCallbackParms)); printf("HfgChannel is %d\r\n", sizeof(HfgChannel)); printf("HfgCallbackParms is %d\r\n", sizeof(HfgCallbackParms)); printf("A2dpStream is %d\r\n", sizeof(A2dpStream)); printf("A2dpCallbackParms is %d\r\n", sizeof(A2dpCallbackParms)); printf("AvdtpStream is %d\r\n", sizeof(AvdtpStream)); printf("AvdtpConn is %d\r\n", sizeof(AvdtpConn)); printf("AvdtpCallbackParms is %d\r\n", sizeof(AvdtpCallbackParms)); printf("AvctpCallbackParms is %d\r\n", sizeof(AvctpCallbackParms)); printf("AvctpChannel is %d\r\n", sizeof(AvctpChannel)); printf("AvctpCmdFrame is %d\r\n", sizeof(AvctpCmdFrame)); printf("AvctpRspFrame is %d\r\n", sizeof(AvctpRspFrame)); printf("AvrcpChannel is %d\r\n", sizeof(AvrcpChannel)); printf("AvrcpCallbackParms is %d\r\n", sizeof(AvrcpCallbackParms)); printf("AvrcpAdvancedPdu is %d\r\n", sizeof(AvrcpAdvancedPdu)); printf("AvrcpPlayerSetting is %d\r\n", sizeof(AvrcpPlayerSetting)); printf("AvrcpPlayerStrings is %d\r\n", sizeof(AvrcpPlayerStrings)); printf("AvrcpEqString is %d\r\n", sizeof(AvrcpEqString)); printf("AvrcpRepeatString is %d\r\n", sizeof(AvrcpRepeatString)); printf("AvrcpShuffleString is %d\r\n", sizeof(AvrcpShuffleString)); printf("AvrcpScanString is %d\r\n", sizeof(AvrcpScanString)); printf("AvrcpExtString is %d\r\n", sizeof(AvrcpExtString)); printf("AvrcpCharSets is %d\r\n", sizeof(AvrcpCharSets)); printf("AvrcpMediaInfo is %d\r\n", sizeof(AvrcpMediaInfo)); printf("AvrcpMediaPlayStatus is %d\r\n", sizeof(AvrcpMediaPlayStatus)); printf("AvrcpTrackStruct is %d\r\n", sizeof(AvrcpTrackStruct)); } void app_bt_send_sco_data(void *channel, uint8_t seq, uint8_t *data, uint16_t length) { BtPacket *sco_packet; HfChannel *Chan = channel; uint16_t data_length; uint8_t sub_seq = 0; uint8_t index; BtStatus status = BT_STATUS_SUCCESS; sco_packet = btdm_malloc(sizeof(BtPacket)); if (sco_packet) { memset((void *)sco_packet, 0, sizeof(BtPacket)); if (length == 57) { data_length = 60; sco_packet->data = btdm_malloc(data_length); sco_packet->data[0] = 0x01; if (seq & 0x01) { sub_seq = 0x30; } if (seq & 0x02) { sub_seq |= 0xc0; } sco_packet->data[1] = 0x08 | sub_seq; memcpy(&sco_packet->data[2], data, length); sco_packet->data[59] = 0x00; sco_packet->dataLen = data_length; } else { sco_packet->data = btdm_malloc(length); memcpy(sco_packet->data, data, length); sco_packet->dataLen = length; } for(index = 0; index < NUM_BT_DEVICES; index++) { if((uint32_t)&hfg_channel[index] == (uint32_t)channel){ status = HFG_SendAudioData((HfgChannel *)Chan, sco_packet); break; } else if((uint32_t)&hf_channel[index] == (uint32_t)channel){ status = HF_SendAudioData((HfChannel *)Chan, sco_packet); break; } } if((index == NUM_BT_DEVICES) || (status != BT_STATUS_PENDING)){ btdm_free(sco_packet->data); btdm_free(sco_packet); } } } void app_bt_init(void) { // app_btdm_struct_size_dump(); #define EIR_DATA_SIZE 50 uint8_t eir_data[EIR_DATA_SIZE]; uint8_t index = 0; uint8_t rand_num[4]; uint8_t hex_2_char[] = {'0', '1', '2','3', '4', '5','6', '7', '8','9', 'a', 'b','c', 'd', 'e', 'f'}; #if BTDM_STACK_ENABLE_HF hf_channel = btdm_malloc(sizeof(HfChannel) * NUM_BT_DEVICES); #endif #if BTDM_STACK_ENABLE_AG hfg_channel = btdm_malloc(sizeof(HfgChannel) * NUM_BT_DEVICES); #endif Stream = btdm_malloc(sizeof(A2dpStream) * NUM_STREAMS); #if BTDM_STACK_ENABLE_AVRCP rcpCtChannel = btdm_malloc(sizeof(AvrcpChannel) * NUM_BT_DEVICES); rcpTgChannel = btdm_malloc(sizeof(AvrcpChannel) * NUM_BT_DEVICES); #endif // scoPacket = btdm_malloc(sizeof(BtPacket)); // memset((void *)scoPacket, 0, sizeof(BtPacket)); // scoPacket->data = btdm_malloc(120); ME_InitHandler(&securityHandler); securityHandler.callback = security_event_handler; SEC_RegisterPairingHandler(&securityHandler); SEC_RegisterAuthorizeHandler(&securityHandler); /* Set our promiscuous link policies */ ME_SetDefaultLinkPolicy(((BLP_MASTER_SLAVE_SWITCH|BLP_SNIFF_MODE)&(~BLP_MASK)), ((BLP_MASTER_SLAVE_SWITCH|BLP_SNIFF_MODE)&(~BLP_MASK))); #if BT_ADDR_RANDOM_ENABLE if(flashdb_get(FDB_KEY_USER_RANDOM_SEED, (void *)&rand_num[0], 4) != 0){ default_name[7] = hex_2_char[(rand_num[1]&0xf0) >> 4]; default_name[8] = hex_2_char[(rand_num[1]&0x0f)]; default_name[9] = hex_2_char[(rand_num[0]&0xf0) >> 4]; default_name[10] = hex_2_char[(rand_num[0]&0x0f)]; } #endif ME_SetLocalDeviceName((const uint8_t *)default_name, sizeof(default_name)); memset(&eir_data[0],0,EIR_DATA_SIZE); eir_data[index++] = sizeof(default_name) + 1; eir_data[index++] = 0x09; memcpy(&(eir_data[index]),default_name,sizeof(default_name)); ME_SetExtInquiryRsp(0x01,eir_data,sizeof(default_name)+1); SEC_SetBondingMode(GENERAL_BONDING); SEC_SetIoCapabilities(IO_NO_IO); ME_InitHandler(&(globalHandler)); globalHandler.callback = me_callback; ME_RegisterGlobalHandler(&globalHandler); // ME_SetEventMask(&globalHandler, (BEM_ACCESSIBLE_CHANGE | // BEM_LINK_CONNECT_CNF | // BEM_LINK_CONNECT_IND | // BEM_LINK_DISCONNECT | // BEM_ROLE_CHANGE | // BEM_MODE_CHANGE | // BEM_INQUIRY_COMPLETE | // BEM_INQUIRY_RESULT | // BEM_INQUIRY_CANCELED)); ME_SetEventMask(&globalHandler, BEM_ALL_EVENTS); ME_RegisterAcceptHandler(&globalHandler); secParms.level = (BSL_SECURITY_L2_IN | BSL_SECURITY_L2_OUT);//HF_SECURITY_SETTINGS; secParms.pinLen = 4; #if BTDM_STACK_ENABLE_HF HF_SetSupportedFeature(HF_SDK_FEATURES); for (uint8_t i=0; i<NUM_BT_DEVICES; i++) { HF_RegisterSec(&hf_channel[i], hf_callback, &secParms); } #endif ME_SetClassOfDevice( COD_AUDIO | COD_MAJOR_AUDIO | COD_MINOR_AUDIO_HANDSFREE); #if BTDM_STACK_ENABLE_AG HFG_SetSupportedFeature(HFG_SDK_FEATURES); for (uint8_t i=0; i<NUM_BT_DEVICES; i++) { HFG_RegisterSec(&hfg_channel[i], hfg_callback, &secParms); } #endif #if BTDM_STACK_ENABLE_A2DP_SNK /* Register SBC stream sink */ sbcSnkCodec1.codecType = AVDTP_CODEC_TYPE_SBC; sbcSnkCodec1.elemLen = sizeof(SbcSnkElements); sbcSnkCodec1.elements = SbcSnkElements; #if BTDM_STACK_ENABLE_AAC aacSnkCodec1.codecType = AVDTP_CODEC_TYPE_MPEG2_4_AAC; aacSnkCodec1.elemLen = sizeof(AacSnkElements); aacSnkCodec1.elements = AacSnkElements; #else sbcSnkCodec2.codecType = AVDTP_CODEC_TYPE_SBC; sbcSnkCodec2.elemLen = sizeof(SbcSnkElements); sbcSnkCodec2.elements = SbcSnkElements; #endif Stream[0].type = A2DP_STREAM_TYPE_SINK; Stream[1].type = A2DP_STREAM_TYPE_SINK; A2DP_Register(&Stream[0], &sbcSnkCodec1, a2dp_callback); #if BTDM_STACK_ENABLE_AAC A2DP_Register(&Stream[1], &aacSnkCodec1, a2dp_callback); #else A2DP_Register(&Stream[1], &sbcSnkCodec2, a2dp_callback); #endif #endif #if BTDM_STACK_ENABLE_PAN PanService pan_service; pan_service.type = 0x1115; // PANU pan_service.callback = pan_callback; PAN_Register(&pan_service); bnep_lwip_init(); #endif #if BTDM_STACK_ENABLE_A2DP_SRC /* Register SBC stream src */ sbcSrcCodec1.codecType = AVDTP_CODEC_TYPE_SBC; sbcSrcCodec1.elemLen = sizeof(SbcSrcElements); sbcSrcCodec1.elements = SbcSrcElements; Stream[2].type = A2DP_STREAM_TYPE_SOURCE; Stream[3].type = A2DP_STREAM_TYPE_SOURCE; A2DP_Register(&Stream[2], &sbcSrcCodec1, a2dp_callback); A2DP_Register(&Stream[3], &sbcSrcCodec1, a2dp_callback); #endif // AVDEV_ListenSignalLink(a2dp_device_callback); #if BTDM_STACK_ENABLE_AVRCP || BTDM_STACK_ENABLE_A2DP_SNK || BTDM_STACK_ENABLE_A2DP_SRC for (uint8_t i=0; i<NUM_BT_DEVICES; i++) { AVRCP_RegisterSec(&rcpCtChannel[i], avrcp_callback, AVRCP_CT|AVRCP_TG, &secParms); #if AVRCP_ADVANCED_TARGET == XA_ENABLED AVRCP_TgSetEventMask(&rcpCtChannel[i], AVRCP_ENABLE_VOLUME_CHANGED); #endif //AVRCP_RegisterSec(&rcpTgChannel[i], avrcp_callback, AVRCP_TG, &secParms); } #endif ME_SetAccessibleModeC(BAM_NOT_ACCESSIBLE, &access_mode_nc); ME_SetAccessibleModeNC(BAM_GENERAL_ACCESSIBLE, &access_mode_nc); } 打印完[INFO] me_callback :105,151就卡死了为什么 c语言

static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { switch (event) { #ifdef CONFIG_SET_RAW_ADV_DATA case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: adv_config_done &= (~ADV_CONFIG_FLAG); if (adv_config_done == 0){ esp_ble_gap_start_advertising(&adv_params); } break; case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: adv_config_done &= (~SCAN_RSP_CONFIG_FLAG); if (adv_config_done == 0){ esp_ble_gap_start_advertising(&adv_params); } break; #else case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: adv_config_done &= (~ADV_CONFIG_FLAG); if (adv_config_done == 0){ esp_ble_gap_start_advertising(&adv_params); } break; case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: adv_config_done &= (~SCAN_RSP_CONFIG_FLAG); if (adv_config_done == 0){ esp_ble_gap_start_advertising(&adv_params); } break; #endif case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: /* advertising start complete event to indicate advertising start successfully or failed */ if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(GATTS_TABLE_TAG, "advertising start failed"); }else{ ESP_LOGI(GATTS_TABLE_TAG, "advertising start successfully"); } break; case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(GATTS_TABLE_TAG, "Advertising stop failed"); } else { ESP_LOGI(GATTS_TABLE_TAG, "Stop adv successfully"); } break; case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: ESP_LOGI(GATTS_TABLE_TAG, "update connection params status = %d, conn_int = %d, latency = %d, timeout = %d", param->update_conn_params.status, param->update_conn_params.conn_int, param->update_conn_params.latency, param->update_conn_params.timeout); break; default: break; } }那你分析一下这段代码

详细讲解下面的代码: { // 准备存放设备名称和 UUID(16-bit 和 128-bit)的缓存区。 /* inquiry result */ bt_bdname_t bdname; uint8_t remote_name_len; uint8_t num_uuids = 0, num_uuids128 = 0, max_num_uuid = 32; uint8_t uuid_list[32 * Uuid::kNumBytes16]; uint8_t uuid_list128[32 * Uuid::kNumBytes128]; // 根据 EIR 数据判断是否需要发起 Remote Name Request(即设备是否已广播出名称)。 p_search_data->inq_res.remt_name_not_required = check_eir_remote_name(p_search_data, NULL, NULL); // 获取发现设备的地址。 RawAddress& bdaddr = p_search_data->inq_res.bd_addr; BTIF_TRACE_DEBUG("%s() %s device_type = 0x%x\n", __func__, bdaddr.ToString().c_str(), p_search_data->inq_res.device_type); bdname.name[0] = 0; // 尝试从 EIR 中读取名称,失败则从缓存中获取。 if (!check_eir_remote_name(p_search_data, bdname.name, &remote_name_len)) check_cached_remote_name(p_search_data, bdname.name, &remote_name_len); /* Check EIR for services */ // 获取 UUID(服务)信息: if (p_search_data->inq_res.p_eir) { BTM_GetEirUuidList(p_search_data->inq_res.p_eir, p_search_data->inq_res.eir_len, Uuid::kNumBytes16, &num_uuids, uuid_list, max_num_uuid); BTM_GetEirUuidList(p_search_data->inq_res.p_eir, p_search_data->inq_res.eir_len, Uuid::kNumBytes128, &num_uuids128, uuid_list128, max_num_uuid); } { /* 构建属性列表: 将设备属性打包成数组,逐项填充: - 蓝牙地址 - 名称 - 类别(COD) - 类型(BR/EDR、BLE 或 DUAL) - RSSI - 是否支持 CSIP 协调组 - UUID(服务) UUID 部分还会缓存入 eir_uuids_cache,并使用 btif_update_uuid 做去重更新。 */ bt_property_t properties[7]; bt_device_type_t dev_type; uint32_t num_properties = 0; bt_status_t status; tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC; memset(properties, 0, sizeof(properties)); /* RawAddress */ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr); num_properties++; /* BD_NAME */ /* Don't send BDNAME if it is empty */ if (bdname.name[0]) { BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_BDNAME, strlen((char*)bdname.name), &bdname); num_properties++; } /* DEV_CLASS */ uint32_t cod = devclass2uint(p_search_data->inq_res.dev_class); BTIF_TRACE_DEBUG("%s cod is 0x%06x", __func__, cod); if (cod != 0) { BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod); num_properties++; } /* DEV_TYPE */ /* FixMe: Assumption is that bluetooth.h and BTE enums match */ /* Verify if the device is dual mode in NVRAM */ int stored_device_type = 0; if (btif_get_device_type(bdaddr, &stored_device_type) && ((stored_device_type != BT_DEVICE_TYPE_BREDR && p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BREDR) || (stored_device_type != BT_DEVICE_TYPE_BLE && p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE))) { dev_type = (bt_device_type_t)BT_DEVICE_TYPE_DUMO; } else { dev_type = (bt_device_type_t)p_search_data->inq_res.device_type; } if (p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE) addr_type = p_search_data->inq_res.ble_addr_type; BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type); num_properties++; /* RSSI */ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_REMOTE_RSSI, sizeof(int8_t), &(p_search_data->inq_res.rssi)); num_properties++; /* CSIP supported device */ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_REMOTE_IS_COORDINATED_SET_MEMBER, sizeof(bool), &(p_search_data->inq_res.include_rsi)); num_properties++; /* Cache EIR queried services */ if ((num_uuids + num_uuids128) > 0) { uint16_t* p_uuid16 = (uint16_t*)uuid_list; auto uuid_iter = eir_uuids_cache.find(bdaddr); Uuid new_remote_uuid[BT_MAX_NUM_UUIDS]; size_t dst_max_num = sizeof(new_remote_uuid)/sizeof(Uuid); size_t new_num_uuid = 0; Uuid remote_uuid[BT_MAX_NUM_UUIDS]; if (uuid_iter == eir_uuids_cache.end()) { auto triple = eir_uuids_cache.try_emplace(bdaddr, std::set<Uuid>{}); uuid_iter = std::get<0>(triple); } //LOG_INFO("EIR UUIDs for %s:", bdaddr.ToString().c_str()); for (int i = 0; i < num_uuids; ++i) { Uuid uuid = Uuid::From16Bit(p_uuid16[i]); //LOG_INFO(" %s", uuid.ToString().c_str()); uuid_iter->second.insert(uuid); if (i < BT_MAX_NUM_UUIDS) { remote_uuid[i] = uuid; } else { LOG_INFO("%d >= %d", i, BT_MAX_NUM_UUIDS); } } for (int i = 0; i < num_uuids128; ++i) { Uuid uuid = Uuid::From128BitBE((uint8_t *)&uuid_list128[i * Uuid::kNumBytes128]); //LOG_INFO(" %s", uuid.ToString().c_str()); uuid_iter->second.insert(uuid); if (i < BT_MAX_NUM_UUIDS) { remote_uuid[num_uuids + i] = uuid; } else { LOG_INFO("%d >= %d", i, BT_MAX_NUM_UUIDS); } } //LOG_INFO("%s %d : update EIR UUIDs.", __func__, __LINE__); new_num_uuid = btif_update_uuid(bdaddr, remote_uuid, (num_uuids + num_uuids128), new_remote_uuid, sizeof(new_remote_uuid), dst_max_num); BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_UUIDS, new_num_uuid * Uuid::kNumBytes128, new_remote_uuid); //LOG_INFO("%s %d : fill BT_PROPERTY_UUIDS property.", __func__, __LINE__); num_properties ++; } // 持久化 & 回调: status = btif_storage_add_remote_device(&bdaddr, num_properties, properties); // 添加进本地数据库 ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device (inquiry)", status); status = btif_storage_set_remote_addr_type(&bdaddr, addr_type); // 保存 BLE 地址类型 ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote addr type (inquiry)", status); bool restrict_report = osi_property_get_bool( "bluetooth.restrict_discovered_device.enabled", false); // 限制上报策略, 可选地根据系统属性是否限制上报某些设备。 if (restrict_report && p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE && !(p_search_data->inq_res.ble_evt_type & BTM_BLE_CONNECTABLE_MASK)) { LOG_INFO("%s: Ble device is not connectable", bdaddr.ToString().c_str()); break; } // 上报到上层(Java 层): 触发 BluetoothAdapter.onBluetoothDeviceFound() 等 Java 层通知。 /* Callback to notify upper layer of device */ invoke_device_found_cb(num_properties, properties); } }

#include "Dri_BT.h" // 定义蓝牙状态 static bool bt_initialized = false; /* 定义esp32收到手机数据时的回调弱函数 */ void __attribute__((weak)) App_Communication_DealBtData(uint8_t *data, uint16_t dataLen) { } // 设置蓝牙名称 static char example_device_name[ESP_BLE_ADV_NAME_LEN_MAX] = "Zkevin_SmartHumidifier"; static uint8_t adv_config_done = 0; static uint16_t heart_rate_handle_table[HRS_IDX_NB]; static uint8_t test_manufacturer[3] = {'E', 'S', 'P'}; static uint8_t sec_service_uuid[16] = { /* LSB <--------------------------------------------------------------------------------> MSB */ // first uuid, 16bit, [12],[13] is the value 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00, }; // config adv data static esp_ble_adv_data_t heart_rate_adv_config = { .set_scan_rsp = false, .include_txpower = true, .min_interval = 0x0006, // slave connection min interval, Time = min_interval * 1.25 msec .max_interval = 0x0010, // slave connection max interval, Time = max_interval * 1.25 msec .appearance = 0x00, .manufacturer_len = 0, // TEST_MANUFACTURER_DATA_LEN, .p_manufacturer_data = NULL, //&test_manufacturer[0], .service_data_len = 0, .p_service_data = NULL, .service_uuid_len = sizeof(sec_service_uuid), .p_service_uuid = sec_service_uuid, .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), }; // config scan response data static esp_ble_adv_data_t heart_rate_scan_rsp_config = { .set_scan_rsp = true, .include_name = true, .manufacturer_len = sizeof(test_manufacturer), .p_manufacturer_data = test_manufacturer, }; static esp_ble_adv_params_t heart_rate_adv_params = { .adv_int_min = 0x100, .adv_int_max = 0x100, .adv_type = ADV_TYPE_IND, .own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC, .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; struct gatts_profile_inst { esp_gatts_cb_t gatts_cb; uint16_t gatts_if; uint16_t app_id; uint16_t conn_id; uint16_t service_handle; esp_gatt_srvc_id_t service_id; uint16_t char_handle; esp_bt_uuid_t char_uuid; esp_gatt_perm_t perm; esp_gatt_char_prop_t property; uint16_t descr_handle; esp_bt_uuid_t descr_uuid; }; static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); /* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */ static struct gatts_profile_inst heart_rate_profile_tab[HEART_PROFILE_NUM] = { [HEART_PROFILE_APP_IDX] = { .gatts_cb = gatts_profile_event_handler, .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ }, }; /* * Heart Rate PROFILE ATTRIBUTES **************************************************************************************** */ /// Heart Rate Sensor Service static const uint16_t heart_rate_svc = ESP_GATT_UUID_HEART_RATE_SVC; #define CHAR_DECLARATION_SIZE (sizeof(uint8_t)) static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE; static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY; static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ; static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ; /// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify static const uint16_t heart_rate_meas_uuid = ESP_GATT_HEART_RATE_MEAS; static const uint8_t heart_measurement_ccc[2] = {0x00, 0x00}; /// Heart Rate Sensor Service -Body Sensor Location characteristic, read static const uint16_t body_sensor_location_uuid = ESP_GATT_BODY_SENSOR_LOCATION; static const uint8_t body_sensor_loc_val[1] = {0x00}; /// Heart Rate Sensor Service - Heart Rate Control Point characteristic, write&read static const uint16_t heart_rate_ctrl_point = ESP_GATT_HEART_RATE_CNTL_POINT; static const uint8_t heart_ctrl_point[1] = {0x00}; /// Full HRS Database Description - Used to add attributes into the database static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] = { // Heart Rate Service Declaration [HRS_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ, sizeof(uint16_t), sizeof(heart_rate_svc), (uint8_t *)&heart_rate_svc}}, // Heart Rate Measurement Characteristic Declaration [HRS_IDX_HR_MEAS_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}}, // Heart Rate Measurement Characteristic Value [HRS_IDX_HR_MEAS_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_meas_uuid, ESP_GATT_PERM_READ, HRPS_HT_MEAS_MAX_LEN, 0, NULL}}, // Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor [HRS_IDX_HR_MEAS_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}}, // Body Sensor Location Characteristic Declaration [HRS_IDX_BOBY_SENSOR_LOC_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}}, // Body Sensor Location Characteristic Value [HRS_IDX_BOBY_SENSOR_LOC_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&body_sensor_location_uuid, ESP_GATT_PERM_READ_ENCRYPTED, sizeof(uint8_t), sizeof(body_sensor_loc_val), (uint8_t *)body_sensor_loc_val}}, // Heart Rate Control Point Characteristic Declaration [HRS_IDX_HR_CTNL_PT_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write}}, // Heart Rate Control Point Characteristic Value [HRS_IDX_HR_CTNL_PT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_ctrl_point, ESP_GATT_PERM_WRITE_ENCRYPTED | ESP_GATT_PERM_READ_ENCRYPTED, sizeof(uint8_t), sizeof(heart_ctrl_point), (uint8_t *)heart_ctrl_point}}, }; static char *esp_key_type_to_str(esp_ble_key_type_t key_type) { char *key_str = NULL; switch (key_type) { case ESP_LE_KEY_NONE: key_str = "ESP_LE_KEY_NONE"; break; case ESP_LE_KEY_PENC: key_str = "ESP_LE_KEY_PENC"; break; case ESP_LE_KEY_PID: key_str = "ESP_LE_KEY_PID"; break; case ESP_LE_KEY_PCSRK: key_str = "ESP_LE_KEY_PCSRK"; break; case ESP_LE_KEY_PLK: key_str = "ESP_LE_KEY_PLK"; break; case ESP_LE_KEY_LLK: key_str = "ESP_LE_KEY_LLK"; break; case ESP_LE_KEY_LENC: key_str = "ESP_LE_KEY_LENC"; break; case ESP_LE_KEY_LID: key_str = "ESP_LE_KEY_LID"; break; case ESP_LE_KEY_LCSRK: key_str = "ESP_LE_KEY_LCSRK"; break; default: key_str = "INVALID BLE KEY TYPE"; break; } return key_str; } static char *esp_auth_req_to_str(esp_ble_auth_req_t auth_req) { char *auth_str = NULL; switch (auth_req) { case ESP_LE_AUTH_NO_BOND: auth_str = "ESP_LE_AUTH_NO_BOND"; break; case ESP_LE_AUTH_BOND: auth_str = "ESP_LE_AUTH_BOND"; break; case ESP_LE_AUTH_REQ_MITM: auth_str = "ESP_LE_AUTH_REQ_MITM"; break; case ESP_LE_AUTH_REQ_BOND_MITM: auth_str = "ESP_LE_AUTH_REQ_BOND_MITM"; break; case ESP_LE_AUTH_REQ_SC_ONLY: auth_str = "ESP_LE_AUTH_REQ_SC_ONLY"; break; case ESP_LE_AUTH_REQ_SC_BOND: auth_str = "ESP_LE_AUTH_REQ_SC_BOND"; break; case ESP_LE_AUTH_REQ_SC_MITM: auth_str = "ESP_LE_AUTH_REQ_SC_MITM"; break; case ESP_LE_AUTH_REQ_SC_MITM_BOND: auth_str = "ESP_LE_AUTH_REQ_SC_MITM_BOND"; break; default: auth_str = "INVALID BLE AUTH REQ"; break; } return auth_str; } static void show_bonded_devices(void) { int dev_num = esp_ble_get_bond_device_num(); if (dev_num == 0) { ESP_LOGI(GATTS_TABLE_TAG, "Bonded devices number zero\n"); return; } esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num); if (!dev_list) { ESP_LOGI(GATTS_TABLE_TAG, "malloc failed, return\n"); return; } esp_ble_get_bond_device_list(&dev_num, dev_list); ESP_LOGI(GATTS_TABLE_TAG, "Bonded devices number %d", dev_num); for (int i = 0; i < dev_num; i++) { ESP_LOGI(GATTS_TABLE_TAG, "[%u] addr_type %u, addr " ESP_BD_ADDR_STR "", i, dev_list[i].bd_addr_type, ESP_BD_ADDR_HEX(dev_list[i].bd_addr)); } free(dev_list); } static void __attribute__((unused)) remove_all_bonded_devices(void) { int dev_num = esp_ble_get_bond_device_num(); if (dev_num == 0) { ESP_LOGI(GATTS_TABLE_TAG, "Bonded devices number zero\n"); return; } esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num); if (!dev_list) { ESP_LOGI(GATTS_TABLE_TAG, "malloc failed, return\n"); return; } esp_ble_get_bond_device_list(&dev_num, dev_list); for (int i = 0; i < dev_num; i++) { esp_ble_remove_bond_device(dev_list[i].bd_addr); } free(dev_list); } static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { ESP_LOGV(GATTS_TABLE_TAG, "GAP_EVT, event %d", event); switch (event) { case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: adv_config_done &= (~SCAN_RSP_CONFIG_FLAG); if (adv_config_done == 0) { esp_ble_gap_start_advertising(&heart_rate_adv_params); } break; case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: adv_config_done &= (~ADV_CONFIG_FLAG); if (adv_config_done == 0) { esp_ble_gap_start_advertising(&heart_rate_adv_params); } break; case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: // advertising start complete event to indicate advertising start successfully or failed if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(GATTS_TABLE_TAG, "Advertising start failed, status %x", param->adv_start_cmpl.status); break; } ESP_LOGI(GATTS_TABLE_TAG, "Advertising start successfully"); break; case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ ESP_LOGI(GATTS_TABLE_TAG, "Passkey request"); /* Call the following function to input the passkey which is displayed on the remote device */ // esp_ble_passkey_reply(heart_rate_profile_tab[HEART_PROFILE_APP_IDX].remote_bda, true, 0x00); break; case ESP_GAP_BLE_OOB_REQ_EVT: { ESP_LOGI(GATTS_TABLE_TAG, "OOB request"); uint8_t tk[16] = {1}; // If you paired with OOB, both devices need to use the same tk esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk)); break; } case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ ESP_LOGI(GATTS_TABLE_TAG, "Local identity root"); break; case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ ESP_LOGI(GATTS_TABLE_TAG, "Local encryption root"); break; case ESP_GAP_BLE_NC_REQ_EVT: /* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability. show the passkey number to the user to confirm it with the number displayed by peer device. */ esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true); ESP_LOGI(GATTS_TABLE_TAG, "Numeric Comparison request, passkey %" PRIu32, param->ble_security.key_notif.passkey); break; case ESP_GAP_BLE_SEC_REQ_EVT: /* send the positive(true) security response to the peer device to accept the security request. If not accept the security request, should send the security response with negative(false) accept value*/ esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); break; case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: /// the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. /// show the passkey number to the user to input it in the peer device. ESP_LOGI(GATTS_TABLE_TAG, "Passkey notify, passkey %06" PRIu32, param->ble_security.key_notif.passkey); break; case ESP_GAP_BLE_KEY_EVT: // shows the ble key info share with peer device to the user. ESP_LOGI(GATTS_TABLE_TAG, "Key exchanged, key_type %s", esp_key_type_to_str(param->ble_security.ble_key.key_type)); break; case ESP_GAP_BLE_AUTH_CMPL_EVT: { esp_bd_addr_t bd_addr; memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t)); ESP_LOGI(GATTS_TABLE_TAG, "Authentication complete, addr_type %u, addr " ESP_BD_ADDR_STR "", param->ble_security.auth_cmpl.addr_type, ESP_BD_ADDR_HEX(bd_addr)); if (!param->ble_security.auth_cmpl.success) { ESP_LOGI(GATTS_TABLE_TAG, "Pairing failed, reason 0x%x", param->ble_security.auth_cmpl.fail_reason); } else { ESP_LOGI(GATTS_TABLE_TAG, "Pairing successfully, auth_mode %s", esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode)); } show_bonded_devices(); break; } case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: { ESP_LOGD(GATTS_TABLE_TAG, "Bond device remove, status %d, device " ESP_BD_ADDR_STR "", param->remove_bond_dev_cmpl.status, ESP_BD_ADDR_HEX(param->remove_bond_dev_cmpl.bd_addr)); break; } case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT: if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(GATTS_TABLE_TAG, "Local privacy config failed, status %x", param->local_privacy_cmpl.status); break; } ESP_LOGI(GATTS_TABLE_TAG, "Local privacy config successfully"); esp_err_t ret = esp_ble_gap_config_adv_data(&heart_rate_adv_config); if (ret) { ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret); } else { adv_config_done |= ADV_CONFIG_FLAG; } ret = esp_ble_gap_config_adv_data(&heart_rate_scan_rsp_config); if (ret) { ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret); } else { adv_config_done |= SCAN_RSP_CONFIG_FLAG; } break; default: break; } } static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { ESP_LOGV(GATTS_TABLE_TAG, "event = %x", event); switch (event) { case ESP_GATTS_REG_EVT: ESP_LOGI(GATTS_TABLE_TAG, "GATT server register, status %d, app_id %d, gatts_if %d", param->reg.status, param->reg.app_id, gatts_if); esp_ble_gap_set_device_name(example_device_name); // generate a resolvable random address esp_ble_gap_config_local_privacy(true); esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if, HRS_IDX_NB, HEART_RATE_SVC_INST_ID); break; case ESP_GATTS_READ_EVT: break; case ESP_GATTS_WRITE_EVT: ESP_LOGI(GATTS_TABLE_TAG, "Characteristic write, value "); ESP_LOG_BUFFER_HEX(GATTS_TABLE_TAG, param->write.value, param->write.len); App_Communication_DealBtData(param->write.value, param->write.len); break; case ESP_GATTS_EXEC_WRITE_EVT: break; case ESP_GATTS_MTU_EVT: break; case ESP_GATTS_CONF_EVT: break; case ESP_GATTS_UNREG_EVT: break; case ESP_GATTS_DELETE_EVT: break; case ESP_GATTS_START_EVT: break; case ESP_GATTS_STOP_EVT: break; case ESP_GATTS_CONNECT_EVT: ESP_LOGI(GATTS_TABLE_TAG, "Connected, conn_id %u, remote " ESP_BD_ADDR_STR "", param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda)); /* start security connect with peer device when receive the connect event sent by the master */ esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM); break; case ESP_GATTS_DISCONNECT_EVT: ESP_LOGI(GATTS_TABLE_TAG, "Disconnected, remote " ESP_BD_ADDR_STR ", reason 0x%x", ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason); /* start advertising again when missing the connect */ esp_ble_gap_start_advertising(&heart_rate_adv_params); break; case ESP_GATTS_OPEN_EVT: break; case ESP_GATTS_CANCEL_OPEN_EVT: break; case ESP_GATTS_CLOSE_EVT: break; case ESP_GATTS_LISTEN_EVT: break; case ESP_GATTS_CONGEST_EVT: break; case ESP_GATTS_CREAT_ATTR_TAB_EVT: { if (param->create.status == ESP_GATT_OK) { if (param->add_attr_tab.num_handle == HRS_IDX_NB) { ESP_LOGI(GATTS_TABLE_TAG, "Attribute table create successfully, num_handle %x", param->add_attr_tab.num_handle); memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table)); esp_ble_gatts_start_service(heart_rate_handle_table[HRS_IDX_SVC]); } else { ESP_LOGE(GATTS_TABLE_TAG, "Attribute table create abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, HRS_IDX_NB); } } else { ESP_LOGE(GATTS_TABLE_TAG, "Attribute table create failed, error code = %x", param->create.status); } break; } default: break; } } static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { /* If event is register event, store the gatts_if for each profile */ if (event == ESP_GATTS_REG_EVT) { if (param->reg.status == ESP_GATT_OK) { heart_rate_profile_tab[HEART_PROFILE_APP_IDX].gatts_if = gatts_if; } else { ESP_LOGI(GATTS_TABLE_TAG, "Reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status); return; } } do { int idx; for (idx = 0; idx < HEART_PROFILE_NUM; idx++) { if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ gatts_if == heart_rate_profile_tab[idx].gatts_if) { if (heart_rate_profile_tab[idx].gatts_cb) { heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param); } } } } while (0); } /** * @brief 初始化蓝牙模块 * */ void Dri_BT_Init(void) { // 避免重复初始化 if (bt_initialized) { ESP_LOGI(GATTS_TABLE_TAG, "Bluetooth already initialized"); return; } esp_err_t ret; // 获取当前蓝牙状态 esp_bt_controller_status_t bt_status = esp_bt_controller_get_status(); // 蓝牙未被初始化 if (bt_status == ESP_BT_CONTROLLER_STATUS_IDLE) { // 初始化NVS.为了存入蓝牙连接信息; ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // 释放经典蓝牙部署 ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); // 初始化蓝牙硬件配置 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); esp_bt_controller_init(&bt_cfg); esp_bt_controller_enable(ESP_BT_MODE_BLE); // 初始化蓝牙应用层软件配置 esp_bluedroid_init(); esp_bluedroid_enable(); } // 蓝牙未初始化 if (!bt_initialized) { // 注册回调函数 esp_ble_gatts_register_callback(gatts_event_handler); esp_ble_gap_register_callback(gap_event_handler); esp_ble_gatts_app_register(ESP_HEART_RATE_APP_ID); // 设置安全参数,未来传输数据需要加密,采用非对称加密方式(公钥和私钥) esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; // bonding with peer device after authentication esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; // set the IO capability to No output No input uint8_t key_size = 16; // the key size should be 7~16 bytes uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; // 安全密钥 uint32_t passkey = 123456; uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE; uint8_t oob_support = ESP_BLE_OOB_DISABLE; esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); } bt_initialized = true; } #include "Dri_Wifi.h" // 蓝牙的两种情况 // 二维码扫描前需要配网低功耗蓝牙和自定义GATT低功耗蓝牙 // WIFI配网成功后,只需要自定义GATT低功耗蓝牙 typedef enum { BT_MODE_GATT, // GATT服务模式 BT_MODE_DUAL // 双模式(同时支持配网和GATT) } bt_mode_t; // 默认双模式 static bt_mode_t current_bt_mode = BT_MODE_DUAL; static wifi_conn wifi_success_cb; static const char *TAG = "WIFI"; const int WIFI_CONNECTED_EVENT = BIT0; static EventGroupHandle_t wifi_event_group; #define PROV_QR_VERSION "v1" #define PROV_TRANSPORT_BLE "ble" #define QRCODE_BASE_URL "https://espressif.github.io/esp-jumpstart/qrcode.html" // WIFI各种事件的回调函数 static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { // 记录失败次数 static int retries; // 记录WIFI连接失败次数 static uint8_t wifi_conn_retries = 0; if (event_base == WIFI_PROV_EVENT) // WIFI配置事件 { switch (event_id) { case WIFI_PROV_START: ESP_LOGI(TAG, "Provisioning started"); break; case WIFI_PROV_CRED_RECV: { wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data; ESP_LOGI(TAG, "Received Wi-Fi credentials" "\n\tSSID : %s\n\tPassword : %s", (const char *)wifi_sta_cfg->ssid, (const char *)wifi_sta_cfg->password); break; } case WIFI_PROV_CRED_FAIL: { wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data; ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s" "\n\tPlease reset to factory and retry provisioning", (*reason == WIFI_PROV_STA_AUTH_ERROR) ? "Wi-Fi station authentication failed" : "Wi-Fi access-point not found"); retries++; if (retries >= 5) { ESP_LOGI(TAG, "Failed to connect with provisioned AP, resetting provisioned credentials"); wifi_prov_mgr_reset_sm_state_on_failure(); retries = 0; } break; } case WIFI_PROV_CRED_SUCCESS: ESP_LOGI(TAG, "Provisioning successful"); retries = 0; break; case WIFI_PROV_END: // 配置完成后,取消初始化管理器 wifi_prov_mgr_deinit(); break; default: break; } } else if (event_base == WIFI_EVENT) // WIFI事件 { switch (event_id) { case WIFI_EVENT_STA_START: esp_wifi_connect(); break; case WIFI_EVENT_STA_DISCONNECTED: ESP_LOGI(TAG, "Disconnected. Connecting to the AP again..."); wifi_conn_retries++; if (wifi_conn_retries >= 10) { // 重置WIFI配置 wifi_prov_mgr_reset_provisioning(); // 重启芯片 esp_restart(); } esp_wifi_connect(); break; default: break; } } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) // 连接成功 { // 重置记录WIFI连接失败次数 wifi_conn_retries = 0; // 引用运行回调函数代码 wifi_success_cb(); ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; ESP_LOGI(TAG, "Connected with IP Address:" IPSTR, IP2STR(&event->ip_info.ip)); xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT); } else if (event_base == PROTOCOMM_TRANSPORT_BLE_EVENT) // 蓝牙事件 { switch (event_id) { case PROTOCOMM_TRANSPORT_BLE_CONNECTED: ESP_LOGI(TAG, "BLE transport: Connected!"); break; case PROTOCOMM_TRANSPORT_BLE_DISCONNECTED: ESP_LOGI(TAG, "BLE transport: Disconnected!"); break; default: break; } } } static void wifi_init_sta(void) { /* Start Wi-Fi in station mode */ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); } static void get_device_service_name(char *service_name, size_t max) { uint8_t eth_mac[6]; const char *ssid_prefix = "PROV_"; esp_wifi_get_mac(WIFI_IF_STA, eth_mac); snprintf(service_name, max, "%s%02X%02X%02X", ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]); } esp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data) { if (inbuf) { ESP_LOGI(TAG, "Received data: %.*s", inlen, (char *)inbuf); } char response[] = "SUCCESS"; *outbuf = (uint8_t *)strdup(response); if (*outbuf == NULL) { ESP_LOGE(TAG, "System out of memory"); return ESP_ERR_NO_MEM; } *outlen = strlen(response) + 1; /* +1 for NULL terminating byte */ return ESP_OK; } static void wifi_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport) { if (!name || !transport) { ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing."); return; } char payload[150] = {0}; snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" ",\"transport\":\"%s\"}", PROV_QR_VERSION, name, transport); ESP_LOGI(TAG, "Scan this QR code from the provisioning application for Provisioning."); esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT(); esp_qrcode_generate(&cfg, payload); ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload); } /** * @brief 初始化WIFI模块 * */ void Dri_Wifi_Init(wifi_conn wifi_conn_success) { // 赋值回调函数 wifi_success_cb = wifi_conn_success; // 初始化NVS,用于保存WIFI名称于Flash esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ESP_ERROR_CHECK(nvs_flash_init()); } // 初始化TCP/IP ESP_ERROR_CHECK(esp_netif_init()); // 创建事件循环组 ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_event_group = xEventGroupCreate(); // 注册各种事件回调函数 ESP_ERROR_CHECK(esp_event_handler_register(WIFI_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_SECURITY_SESSION_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); // 根据TCP/IP网络协议,初始化WIFI esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // 初始化自定义GATT蓝牙 Dri_BT_Init(); // 配网配置信息 wifi_prov_mgr_config_t config = { .scheme = wifi_prov_scheme_ble, .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM, }; // 配网初始化 ESP_ERROR_CHECK(wifi_prov_mgr_init(config)); bool provisioned = false; // wifi_prov_mgr_reset_provisioning(); // 检查是否配网 ESP_ERROR_CHECK(wifi_prov_mgr_is_provisioned(&provisioned)); // 根据是否配网,做对应操作 // 没有配网 if (!provisioned) { ESP_LOGI(TAG, "Starting provisioning"); // 配网模式:同时支持配网和GATT current_bt_mode = BT_MODE_DUAL; // WIFI设备名称 char service_name[12]; get_device_service_name(service_name, sizeof(service_name)); // 无安全设置 const char *service_key = NULL; // WIFI设备唯一标识 uint8_t custom_service_uuid[] = { /* LSB <--------------------------------------- * ---------------------------------------> MSB */ 0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf, 0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02, }; wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid); // 创建WIFI设备节点信息 wifi_prov_mgr_endpoint_create("custom-data"); // 启动配网设备 wifi_prov_security_t security = WIFI_PROV_SECURITY_0; ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, (const void *)NULL, service_name, service_key)); // 在网络中进行设备注册 wifi_prov_mgr_endpoint_register("custom-data", custom_prov_data_handler, NULL); // 打印二维码 wifi_prov_print_qr(service_name, NULL, NULL, PROV_TRANSPORT_BLE); // 启动双服务广播 start_dual_service_advertising(); } else { ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA"); // 已配网:仅GATT模式 current_bt_mode = BT_MODE_GATT; // 配网初始化 wifi_prov_mgr_deinit(); // 启动WIFI wifi_init_sta(); // 启动GATT服务广播 esp_ble_gap_start_advertising(&heart_rate_adv_params); } // 等待WIFI连接成功 xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY); } 蓝牙的两种情况怎么实现

tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, 743 tBLE_ADDR_TYPE addr_type, 744 tBT_TRANSPORT transport) { 745 tBTM_SEC_DEV_REC* p_dev_rec; 746 tBTM_STATUS status; 747 log::info("Transport used {}, bd_addr={}", transport, bd_addr); 748 749 /* Other security process is in progress */ 750 if (btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) { 751 log::error("BTM_SecBond: already busy in state: {}", 752 tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state)); 753 //#ifdef OPLUS_BT_STACK_UNIFY 754 /* Fix pairing conflict */ 755 if (btm_sec_cb.pairing_bda == bd_addr) { 756 log::warn("same device pairing, return STARTED"); 757 return (BTM_CMD_STARTED); 758 } 759 //#endif /* OPLUS_BT_STACK_UNIFY */ 760 return (BTM_WRONG_MODE); 761 } 762 763 p_dev_rec = btm_find_or_alloc_dev(bd_addr); 764 if (p_dev_rec == NULL) { 765 log::error("No memory to allocate new p_dev_rec"); 766 return (BTM_NO_RESOURCES); 767 } 768 769 //#ifdef OPLUS_BT_STACK_UNIFY 770 /* By default, consider the peer device support SSP when initiating bond */ 771 oplus_smp_sec_bond_support_ssp_default(bd_addr, p_dev_rec); 772 //#endif /* OPLUS_BT_STACK_UNIFY */ 773 774 if (bluetooth::shim::GetController() == nullptr) { 775 log::error("controller module is not ready"); 776 return (BTM_NO_RESOURCES); 777 } 778 779 log::verbose("before update sec_flags=0x{:x}", p_dev_rec->sec_rec.sec_flags); 780 781 /* Finished if connection is active and already paired */ 782 if (((p_dev_rec->hci_handle != HCI_INVALID_HANDLE) && 783 transport == BT_TRANSPORT_BR_EDR && 784 (p_dev_rec->sec_rec.sec_flags & BTM_SEC_AUTHENTICATED)) || 785 ((p_dev_rec->ble_hci_handle != HCI_INVALID_HANDLE) && 786 transport == BT_TRANSPORT_LE && 787 (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_AUTHENTICATED))) { 788 log::warn("BTM_SecBond -> Already Paired"); 789 return (BTM_SUCCESS); 790 } 791 792 /* Tell controller to get rid of the link key if it has one stored */ 793 if ((BTM_DeleteStoredLinkKey(&bd_addr, NULL)) != BTM_SUCCESS) { 794 log::error("Failed to delete stored link keys"); 795 return (BTM_NO_RESOURCES); 796 } 797 798 btm_sec_cb.pairing_bda = bd_addr; 799 800 btm_sec_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD; 801 802 p_dev_rec->sec_rec.security_required = BTM_SEC_OUT_AUTHENTICATE; 803 p_dev_rec->is_originator = true; 804 805 tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, transport); 806 if (p_lcb) { 807 alarm_cancel(p_lcb->l2c_lcb_timer); 808 } 809 810 BTM_LogHistory(kBtmLogTag, bd_addr, "Bonding initiated", 811 bt_transport_text(transport)); 812 813 if (transport == BT_TRANSPORT_LE) { 814 btm_ble_init_pseudo_addr(p_dev_rec, bd_addr); 815 p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LE_MASK; 816 817 if (SMP_Pair(bd_addr, addr_type) == SMP_STARTED) { 818 btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE; 819 p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_AUTHENTICATING; 820 btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); 821 return BTM_CMD_STARTED; 822 } 823 824 btm_sec_cb.pairing_flags = 0; 825 return (BTM_NO_RESOURCES); 826 } 827 828 p_dev_rec->sec_rec.sec_flags &= 829 ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | 830 BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED); 831 832 log::verbose("after update sec_flags=0x{:x}", p_dev_rec->sec_rec.sec_flags); 833 if (!bluetooth::shim::GetController()->SupportsSimplePairing()) { 834 /* The special case when we authenticate keyboard. Set pin type to fixed */ 835 /* It would be probably better to do it from the application, but it is */ 836 /* complicated */ 837 if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == 838 BTM_COD_MAJOR_PERIPHERAL) && 839 (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) && 840 (btm_sec_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) { 841 btm_sec_cb.pin_type_changed = true; 842 btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED); 843 } 844 } 845 846 log::verbose("BTM_SecBond: Remote sm4: 0x{:x} HCI Handle: 0x{:04x}", 847 p_dev_rec->sm4, p_dev_rec->hci_handle); 848 849 /* If connection already exists... */ 850 if (BTM_IsAclConnectionUpAndHandleValid(bd_addr, transport)) { 851 log::debug("An ACL connection currently exists peer:{} transport:{}", 852 bd_addr, bt_transport_text(transport)); 853 btm_sec_wait_and_start_authentication(p_dev_rec); 854 855 btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); 856 857 /* Mark lcb as bonding */ 858 l2cu_update_lcb_4_bonding(bd_addr, true); 859 return (BTM_CMD_STARTED); 860 } 861 log::debug("An ACL connection does not currently exist peer:{} transport:{}", 862 bd_addr, bt_transport_text(transport)); 863 864 log::verbose("sec mode: {} sm4:x{:x}", btm_sec_cb.security_mode, 865 p_dev_rec->sm4); 866 if (!bluetooth::shim::GetController()->SupportsSimplePairing() || 867 (p_dev_rec->sm4 == BTM_SM4_KNOWN)) { 868 if (btm_sec_check_prefetch_pin(p_dev_rec)) { 869 log::debug("Class of device used to check for pin peer:{} transport:{}", 870 bd_addr, bt_transport_text(transport)); 871 return (BTM_CMD_STARTED); 872 } 873 } 874 if ((btm_sec_cb.security_mode == BTM_SEC_MODE_SP || 875 btm_sec_cb.security_mode == BTM_SEC_MODE_SC) && 876 BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) { 877 /* local is 2.1 and peer is unknown */ 878 if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) { 879 #ifdef OPLUS_FEATURE_BT_HS_CONNECT 880 //[email protected], 2021/03/12 881 //If the remote device uses version 2.1 or later, the RNR process will not be performed 882 if (oplus_support_acl_optimize(bd_addr)) { 883 status = btm_sec_dd_create_conn(p_dev_rec); 884 } else { 885 btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); 886 #ifdef OPLUS_FEATURE_BT_DCS 887 report_pair_do_rnr_flag(bd_addr,true); 888 #endif 889 status = BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR); 890 } 891 #else /*OPLUS_FEATURE_BT_HS_CONNECT*/ 892 /* we are not accepting connection request from peer 893 * -> RNR (to learn if peer is 2.1) 894 * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */ 895 btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); 896 status = BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR); 897 #endif /*OPLUS_FEATURE_BT_HS_CONNECT*/ 898 } else { 899 /* We are accepting connection request from peer */ 900 btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); 901 status = BTM_CMD_STARTED; 902 } 903 log::verbose("State:{} sm4: 0x{:x} sec_state:{}", 904 tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), 905 p_dev_rec->sm4, p_dev_rec->sec_rec.sec_state); 906 } else { 907 /* both local and peer are 2.1 */ 908 //#ifdef OPLUS_BT_STACK_UNIFY 909 /* Enable authentication to avoid the peer device is before 2.1 */ 910 btm_sec_cb.security_mode_changed = true; 911 btsnd_hcic_write_auth_enable(true); 912 //#endif /* OPLUS_BT_STACK_UNIFY */ 913 status = btm_sec_dd_create_conn(p_dev_rec); 914 } 915 916 if (status != BTM_CMD_STARTED) { 917 log::error( 918 "BTM_ReadRemoteDeviceName or btm_sec_dd_create_conn error: 0x{:x}", 919 (int)status); 920 btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); 921 } 922 923 return status; 924 } 这个函数闯入的参数是(xx:xx:xx:xx:87:d9,public, BT_TRANSPORT_BR_EDR) 函数的流程会怎么走

AnnotateLine# Scopes# Navigate#Raw Download current directory 1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "bt_bta_sd" 18 19 #include "bta/dm/bta_dm_device_search.h" 20 21 #include <base/functional/bind.h> 22 #include <base/strings/stringprintf.h> 23 #include <bluetooth/log.h> 24 #include <com_android_bluetooth_flags.h> 25 #include <stddef.h> 26 27 #include <cstdint> 28 #include <string> 29 #include <variant> 30 #include <vector> 31 32 #include "bta/dm/bta_dm_device_search_int.h" 33 #include "bta/dm/bta_dm_disc_legacy.h" 34 #include "bta/include/bta_gatt_api.h" 35 #include "bta/include/bta_sdp_api.h" 36 #include "btif/include/btif_config.h" 37 #include "com_android_bluetooth_flags.h" 38 #include "common/circular_buffer.h" 39 #include "common/init_flags.h" 40 #include "common/strings.h" 41 #include "device/include/interop.h" 42 #include "internal_include/bt_target.h" 43 #include "main/shim/dumpsys.h" 44 #include "os/logging/log_adapter.h" 45 #include "osi/include/allocator.h" 46 #include "stack/btm/btm_int_types.h" // TimestampedStringCircularBuffer 47 #include "stack/btm/neighbor_inquiry.h" 48 #include "stack/include/bt_dev_class.h" 49 #include "stack/include/bt_name.h" 50 #include "stack/include/bt_uuid16.h" 51 #include "stack/include/btm_client_interface.h" 52 #include "stack/include/btm_inq.h" 53 #include "stack/include/btm_log_history.h" 54 #include "stack/include/btm_sec_api.h" // BTM_IsRemoteNameKnown 55 #include "stack/include/gap_api.h" // GAP_BleReadPeerPrefConnParams 56 #include "stack/include/hidh_api.h" 57 #include "stack/include/main_thread.h" 58 #include "stack/include/sdp_status.h" 59 #include "stack/sdp/sdpint.h" // is_sdp_pbap_pce_disabled 60 #include "storage/config_keys.h" 61 #include "types/raw_address.h" 62 //#ifdef OPLUS_BUG_STABILITY 63 //[email protected], 2024/09/12 64 //Add for address mask output 65 #include "oplus_bt_util.h" 66 //#endif /* OPLUS_BUG_STABILITY */ 67 68 #ifdef OPLUS_FEATURE_BT_HS_INQUIRY 69 #include "btif/include/btif_dm.h" 70 //[email protected], 2021/03/09 71 //add for fast inquiry 72 #include "oplus_bt_stack_scan_manager.h" 73 extern tBTM_CB btm_cb; 74 #endif 75 76 #ifdef OPLUS_FEATURE_BT_HS_SDP 77 //[email protected], 2023/10/15 78 #include "oplus_bt_stack_sdp_manager.h" 79 #endif 80 81 //#ifdef OPLUS_BT_STACK_UNIFY 82 #include "oplus_btif_dm.h" 83 #include "oplus_btif_core.h" 84 //#endif /* OPLUS_BT_STACK_UNIFY */ 85 86 #include "common/include/hardware/oplus_vendor.h" /* OPLUS_BT_STACK_UNIFY */ 87 88 #ifdef OPLUS_FEATURE_BT_HS_INQUIRY 89 //[email protected] 90 #include "oplus_btif_fast_inquiry.h" 91 #include "main/shim/le_scanning_manager.h" 92 93 #ifdef OPLUS_FEATURE_BT_LE_AUDIO 94 #include "oplus_bt_interop.h" 95 #include "btm_ble_adv_data_processor.h" 96 #endif /* OPLUS_FEATURE_BT_LE_AUDIO */ 97 #endif 98 99 using namespace bluetooth; 100 101 namespace { 102 constexpr char kBtmLogTag[] = "DEV_SEARCH"; 103 104 tBTA_DM_SEARCH_CB bta_dm_search_cb; 105 } // namespace 106 107 //#ifdef OPLUS_BUG_COMPATIBILITY 108 //[email protected], 2024/07/22 109 tBTA_DM_SEARCH_CB* bta_dm_get_search_cb() { 110 return &bta_dm_search_cb; 111 } 112 //#endif /* OPLUS_BUG_COMPATIBILITY */ 113 114 static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, 115 uint16_t eir_len); 116 static void bta_dm_inq_cmpl(); 117 static void bta_dm_inq_cmpl_cb(void* p_result); 118 static void bta_dm_search_cmpl(); 119 static void bta_dm_discover_next_device(void); 120 static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p); 121 122 static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, 123 tBT_TRANSPORT transport); 124 static void bta_dm_discover_name(const RawAddress& remote_bd_addr); 125 static void bta_dm_execute_queued_search_request(); 126 static void bta_dm_search_cancel_notify(); 127 static void bta_dm_disable_search(); 128 129 static void bta_dm_search_sm_execute(tBTA_DM_DEV_SEARCH_EVT event, 130 std::unique_ptr<tBTA_DM_SEARCH_MSG> msg); 131 static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, 132 const uint8_t* p_eir, uint16_t eir_len); 133 static void bta_dm_observe_cmpl_cb(void* p_result); 134 135 static void bta_dm_search_set_state(tBTA_DM_DEVICE_SEARCH_STATE state) { 136 bta_dm_search_cb.search_state = state; 137 } 138 static tBTA_DM_DEVICE_SEARCH_STATE bta_dm_search_get_state() { 139 return bta_dm_search_cb.search_state; 140 } 141 142 static void post_search_evt(tBTA_DM_DEV_SEARCH_EVT event, 143 std::unique_ptr<tBTA_DM_SEARCH_MSG> msg) { 144 if (do_in_main_thread(FROM_HERE, base::BindOnce(&bta_dm_search_sm_execute, 145 event, std::move(msg))) != 146 BT_STATUS_SUCCESS) { 147 log::error("post_search_evt failed"); 148 } 149 } 150 151 void bta_dm_disc_disable_search() { 152 if (!com::android::bluetooth::flags:: 153 separate_service_and_device_discovery()) { 154 log::info("no-op when flag is disabled"); 155 return; 156 } 157 bta_dm_disable_search(); 158 } 159 160 /******************************************************************************* 161 * 162 * Function bta_dm_search_start 163 * 164 * Description Starts an inquiry 165 * 166 * 167 * Returns void 168 * 169 ******************************************************************************/ 170 static void bta_dm_search_start(tBTA_DM_API_SEARCH& search) { 171 #ifdef OPLUS_FEATURE_BT_HS_INQUIRY 172 //[email protected] 173 if(get_fast_act_interface()->enable_inquiry_optimize()) { 174 bluetooth::shim::initAddressCacheExt(); 175 } 176 #endif 177 178 #ifdef OPLUS_FEATURE_BT_HS_INQUIRY 179 //[email protected], 2021/03/09 180 if (btm_cb.btm_inq_vars.inq_num == 0) { 181 get_btm_client_interface().db.BTM_ClearInqDb(nullptr); 182 } 183 #else /* OPLUS_FEATURE_BT_HS_INQUIRY */ 184 if (get_btm_client_interface().db.BTM_ClearInqDb(nullptr) != BTM_SUCCESS) { 185 log::warn("Unable to clear inquiry database for device discovery"); 186 } 187 #endif/*OPLUS_FEATURE_BT_HS_INQUIRY*/ 188 /* save search params */ 189 bta_dm_search_cb.p_device_search_cback = search.p_cback; 190 191 const tBTM_STATUS btm_status = 192 BTM_StartInquiry(bta_dm_inq_results_cb, bta_dm_inq_cmpl_cb); 193 switch (btm_status) { 194 case BTM_CMD_STARTED: 195 // Completion callback will be executed when controller inquiry 196 // timer pops or is cancelled by the user 197 break; 198 default: 199 log::warn("Unable to start device discovery search btm_status:{}", 200 btm_status_text(btm_status)); 201 // Not started so completion callback is executed now 202 bta_dm_inq_cmpl(); 203 break; 204 } 205 } 206 207 /******************************************************************************* 208 * 209 * Function bta_dm_search_cancel 210 * 211 * Description Cancels an ongoing search for devices 212 * 213 * 214 * Returns void 215 * 216 ******************************************************************************/ 217 static void bta_dm_search_cancel() { 218 if (BTM_IsInquiryActive()) { 219 BTM_CancelInquiry(); 220 bta_dm_search_cancel_notify(); 221 bta_dm_search_cmpl(); 222 } 223 /* If no Service Search going on then issue cancel remote name in case it is 224 active */ 225 else if (!bta_dm_search_cb.name_discover_done) { 226 if (get_btm_client_interface().peer.BTM_CancelRemoteDeviceName() != 227 BTM_CMD_STARTED) { 228 log::warn("Unable to cancel RNR"); 229 } 230 /* bta_dm_search_cmpl is called when receiving the remote name cancel evt */ 231 if (!com::android::bluetooth::flags:: 232 bta_dm_defer_device_discovery_state_change_until_rnr_complete()) { 233 bta_dm_search_cmpl(); 234 } 235 } else { 236 bta_dm_inq_cmpl(); 237 } 238 } 239 240 /******************************************************************************* 241 * 242 * Function bta_dm_inq_cmpl_cb 243 * 244 * Description Inquiry complete callback from BTM 245 * 246 * Returns void 247 * 248 ******************************************************************************/ 249 static void bta_dm_inq_cmpl_cb(void* /* p_result */) { 250 log::verbose(""); 251 252 bta_dm_inq_cmpl(); 253 } 254 255 /******************************************************************************* 256 * 257 * Function bta_dm_inq_results_cb 258 * 259 * Description Inquiry results callback from BTM 260 * 261 * Returns void 262 * 263 ******************************************************************************/ 264 static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, 265 uint16_t eir_len) { 266 tBTA_DM_SEARCH result; 267 tBTM_INQ_INFO* p_inq_info; 268 uint16_t service_class; 269 270 result.inq_res.bd_addr = p_inq->remote_bd_addr; 271 272 // Pass the original address to GattService#onScanResult 273 result.inq_res.original_bda = p_inq->original_bda; 274 275 result.inq_res.dev_class = p_inq->dev_class; 276 BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class); 277 result.inq_res.is_limited = 278 (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false; 279 result.inq_res.rssi = p_inq->rssi; 280 281 result.inq_res.ble_addr_type = p_inq->ble_addr_type; 282 result.inq_res.inq_result_type = p_inq->inq_result_type; 283 result.inq_res.device_type = p_inq->device_type; 284 result.inq_res.flag = p_inq->flag; 285 result.inq_res.include_rsi = p_inq->include_rsi; 286 result.inq_res.clock_offset = p_inq->clock_offset; 287 288 /* application will parse EIR to find out remote device name */ 289 result.inq_res.p_eir = const_cast<uint8_t*>(p_eir); 290 result.inq_res.eir_len = eir_len; 291 292 result.inq_res.ble_evt_type = p_inq->ble_evt_type; 293 294 p_inq_info = 295 get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr); 296 if (p_inq_info != NULL) { 297 /* initialize remt_name_not_required to false so that we get the name by 298 * default */ 299 result.inq_res.remt_name_not_required = false; 300 } 301 302 if (bta_dm_search_cb.p_device_search_cback) 303 bta_dm_search_cb.p_device_search_cback(BTA_DM_INQ_RES_EVT, &result); 304 305 if (p_inq_info) { 306 /* application indicates if it knows the remote name, inside the callback 307 copy that to the inquiry data base*/ 308 if (result.inq_res.remt_name_not_required) 309 p_inq_info->appl_knows_rem_name = true; 310 } 311 } 312 313 /******************************************************************************* 314 * 315 * Function bta_dm_remname_cback 316 * 317 * Description Remote name complete call back from BTM 318 * 319 * Returns void 320 * 321 ******************************************************************************/ 322 static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p_remote_name) { 323 log::assert_that(p_remote_name != nullptr, 324 "assert failed: p_remote_name != nullptr"); 325 326 log::info( 327 "Remote name request complete peer:{} btm_status:{} hci_status:{} " 328 "name[0]:{:c} length:{}", 329 p_remote_name->bd_addr, btm_status_text(p_remote_name->status), 330 hci_error_code_text(p_remote_name->hci_status), 331 p_remote_name->remote_bd_name[0], 332 strnlen((const char*)p_remote_name->remote_bd_name, BD_NAME_LEN)); 333 334 if (bta_dm_search_cb.peer_bdaddr != p_remote_name->bd_addr) { 335 // if we got a different response, maybe ignore it 336 // we will have made a request directly from BTM_ReadRemoteDeviceName so we 337 // expect a dedicated response for us 338 if (p_remote_name->hci_status == HCI_ERR_CONNECTION_EXISTS) { 339 log::info( 340 "Assume command failed due to disconnection hci_status:{} peer:{}", 341 hci_error_code_text(p_remote_name->hci_status), 342 p_remote_name->bd_addr); 343 } else { 344 log::info( 345 "Ignored remote name response for the wrong address exp:{} act:{}", 346 bta_dm_search_cb.peer_bdaddr, p_remote_name->bd_addr); 347 return; 348 } 349 } 350 351 /* remote name discovery is done but it could be failed */ 352 bta_dm_search_cb.name_discover_done = true; 353 bd_name_copy(bta_dm_search_cb.peer_name, p_remote_name->remote_bd_name); 354 355 auto msg = std::make_unique<tBTA_DM_SEARCH_MSG>(tBTA_DM_REMOTE_NAME{}); 356 auto& rmt_name_msg = std::get<tBTA_DM_REMOTE_NAME>(*msg); 357 rmt_name_msg.bd_addr = bta_dm_search_cb.peer_bdaddr; 358 rmt_name_msg.hci_status = p_remote_name->hci_status; 359 bd_name_copy(rmt_name_msg.bd_name, p_remote_name->remote_bd_name); 360 361 post_search_evt(BTA_DM_REMT_NAME_EVT, std::move(msg)); 362 } 363 364 /******************************************************************************* 365 * 366 * Function bta_dm_read_remote_device_name 367 * 368 * Description Initiate to get remote device name 369 * 370 * Returns true if started to get remote name 371 * 372 ******************************************************************************/ 373 static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, 374 tBT_TRANSPORT transport) { 375 tBTM_STATUS btm_status; 376 377 log::verbose(""); 378 379 bta_dm_search_cb.peer_bdaddr = bd_addr; 380 bta_dm_search_cb.peer_name[0] = 0; 381 382 btm_status = get_btm_client_interface().peer.BTM_ReadRemoteDeviceName( 383 bta_dm_search_cb.peer_bdaddr, bta_dm_remname_cback, transport); 384 385 if (btm_status == BTM_CMD_STARTED) { 386 log::verbose("BTM_ReadRemoteDeviceName is started"); 387 388 return (true); 389 } else if (btm_status == BTM_BUSY) { 390 log::verbose("BTM_ReadRemoteDeviceName is busy"); 391 392 return (true); 393 } else { 394 log::warn("BTM_ReadRemoteDeviceName returns 0x{:02X}", btm_status); 395 396 return (false); 397 } 398 } 399 400 /******************************************************************************* 401 * 402 * Function bta_dm_inq_cmpl 403 * 404 * Description Process the inquiry complete event from BTM 405 * 406 * Returns void 407 * 408 ******************************************************************************/ 409 static void bta_dm_inq_cmpl() { 410 if (bta_dm_search_get_state() == BTA_DM_SEARCH_CANCELLING) { 411 bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); 412 bta_dm_execute_queued_search_request(); 413 return; 414 } 415 416 if (bta_dm_search_get_state() != BTA_DM_SEARCH_ACTIVE) { 417 return; 418 } 419 420 log::verbose("bta_dm_inq_cmpl"); 421 422 bta_dm_search_cb.p_btm_inq_info = 423 get_btm_client_interface().db.BTM_InqDbFirst(); 424 if (bta_dm_search_cb.p_btm_inq_info != NULL) { 425 /* start name discovery from the first device on inquiry result 426 */ 427 bta_dm_search_cb.name_discover_done = false; 428 bta_dm_search_cb.peer_name[0] = 0; 429 bta_dm_discover_name( 430 bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); 431 } else { 432 bta_dm_search_cmpl(); 433 } 434 } 435 436 static void bta_dm_remote_name_cmpl( 437 const tBTA_DM_REMOTE_NAME& remote_name_msg) { 438 BTM_LogHistory(kBtmLogTag, remote_name_msg.bd_addr, "Remote name completed", 439 base::StringPrintf( 440 "status:%s state:%s name:\"%s\"", 441 hci_status_code_text(remote_name_msg.hci_status).c_str(), 442 bta_dm_state_text(bta_dm_search_get_state()).c_str(), 443 PRIVATE_NAME(remote_name_msg.bd_name))); 444 445 tBTM_INQ_INFO* p_btm_inq_info = 446 get_btm_client_interface().db.BTM_InqDbRead(remote_name_msg.bd_addr); 447 if (!bd_name_is_empty(remote_name_msg.bd_name) && p_btm_inq_info) { 448 #ifdef OPLUS_FEATURE_BT_HS_INQUIRY 449 //[email protected], 2021/03/09 450 //If the Bluetooth device used as RNR has no name before, the address and name information of the device 451 //will be cached to the local file 452 std::string namestr((char*)remote_name_msg.bd_name); 453 log::debug("bta_dm_rmt_name: {},inq_num: {}", 454 obfuscate_name_string(namestr), 455 btm_cb.btm_inq_vars.inq_num); 456 oplus_save_rnr_info_to_file(remote_name_msg.bd_addr,(char*)remote_name_msg.bd_name, 457 bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name); 458 #endif/*OPLUS_FEATURE_BT_HS_INQUIRY*/ 459 p_btm_inq_info->appl_knows_rem_name = true; 460 } 461 462 // Callback with this property 463 if (bta_dm_search_cb.p_device_search_cback != nullptr) { 464 tBTA_DM_SEARCH search_data = { 465 .name_res = {.bd_addr = remote_name_msg.bd_addr, .bd_name = {}}, 466 }; 467 if (remote_name_msg.hci_status == HCI_SUCCESS) { 468 bd_name_copy(search_data.name_res.bd_name, remote_name_msg.bd_name); 469 } 470 bta_dm_search_cb.p_device_search_cback(BTA_DM_NAME_READ_EVT, &search_data); 471 } else { 472 log::warn("Received remote name complete without callback"); 473 } 474 475 switch (bta_dm_search_get_state()) { 476 case BTA_DM_SEARCH_ACTIVE: 477 bta_dm_discover_name(bta_dm_search_cb.peer_bdaddr); 478 break; 479 case BTA_DM_SEARCH_IDLE: 480 case BTA_DM_SEARCH_CANCELLING: 481 log::warn("Received remote name request in state:{}", 482 bta_dm_state_text(bta_dm_search_get_state())); 483 break; 484 } 485 } 486 487 static void bta_dm_search_cmpl() { 488 bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); 489 490 if (bta_dm_search_cb.p_device_search_cback) { 491 bta_dm_search_cb.p_device_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr); 492 } 493 494 bta_dm_execute_queued_search_request(); 495 } 496 497 static void bta_dm_execute_queued_search_request() { 498 if (!bta_dm_search_cb.p_pending_search) return; 499 500 log::info("Start pending search"); 501 post_search_evt(BTA_DM_API_SEARCH_EVT, 502 std::move(bta_dm_search_cb.p_pending_search)); 503 bta_dm_search_cb.p_pending_search.reset(); 504 } 505 506 /******************************************************************************* 507 * 508 * Function bta_dm_search_clear_queue 509 * 510 * Description Clears the queue if API search cancel is called 511 * 512 * Returns void 513 * 514 ******************************************************************************/ 515 static void bta_dm_search_clear_queue() { 516 bta_dm_search_cb.p_pending_search.reset(); 517 } 518 519 /******************************************************************************* 520 * 521 * Function bta_dm_search_cancel_notify 522 * 523 * Description Notify application that search has been cancelled 524 * 525 * Returns void 526 * 527 ******************************************************************************/ 528 static void bta_dm_search_cancel_notify() { 529 if (bta_dm_search_cb.p_device_search_cback) { 530 bta_dm_search_cb.p_device_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL); 531 } 532 switch (bta_dm_search_get_state()) { 533 case BTA_DM_SEARCH_ACTIVE: 534 case BTA_DM_SEARCH_CANCELLING: 535 if (!bta_dm_search_cb.name_discover_done) { 536 if (get_btm_client_interface().peer.BTM_CancelRemoteDeviceName() != 537 BTM_CMD_STARTED) { 538 log::warn("Unable to cancel RNR"); 539 } 540 } 541 break; 542 case BTA_DM_SEARCH_IDLE: 543 // Nothing to do 544 break; 545 } 546 } 547 548 /******************************************************************************* 549 * 550 * Function bta_dm_discover_next_device 551 * 552 * Description Starts discovery on the next device in Inquiry data base 553 * 554 * Returns void 555 * 556 ******************************************************************************/ 557 static void bta_dm_discover_next_device(void) { 558 log::verbose("bta_dm_discover_next_device"); 559 560 /* searching next device on inquiry result */ 561 bta_dm_search_cb.p_btm_inq_info = get_btm_client_interface().db.BTM_InqDbNext( 562 bta_dm_search_cb.p_btm_inq_info); 563 if (bta_dm_search_cb.p_btm_inq_info != NULL) { 564 bta_dm_search_cb.name_discover_done = false; 565 bta_dm_search_cb.peer_name[0] = 0; 566 bta_dm_discover_name( 567 bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); 568 } else { 569 post_search_evt(BTA_DM_SEARCH_CMPL_EVT, nullptr); 570 } 571 } 572 573 /*TODO: this function is duplicated, make it common ?*/ 574 static tBT_TRANSPORT bta_dm_determine_discovery_transport( 575 const RawAddress& remote_bd_addr) { 576 tBT_DEVICE_TYPE dev_type; 577 tBLE_ADDR_TYPE addr_type; 578 579 get_btm_client_interface().peer.BTM_ReadDevInfo(remote_bd_addr, &dev_type, 580 &addr_type); 581 if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM) { 582 return BT_TRANSPORT_LE; 583 } else if (dev_type == BT_DEVICE_TYPE_DUMO) { 584 if (get_btm_client_interface().peer.BTM_IsAclConnectionUp( 585 remote_bd_addr, BT_TRANSPORT_BR_EDR)) { 586 return BT_TRANSPORT_BR_EDR; 587 } else if (get_btm_client_interface().peer.BTM_IsAclConnectionUp( 588 remote_bd_addr, BT_TRANSPORT_LE)) { 589 return BT_TRANSPORT_LE; 590 } 591 } 592 return BT_TRANSPORT_BR_EDR; 593 } 594 595 static void bta_dm_discover_name(const RawAddress& remote_bd_addr) { 596 const tBT_TRANSPORT transport = 597 bta_dm_determine_discovery_transport(remote_bd_addr); 598 599 log::verbose("BDA: {}", remote_bd_addr); 600 601 bta_dm_search_cb.peer_bdaddr = remote_bd_addr; 602 603 log::verbose( 604 "name_discover_done = {} p_btm_inq_info 0x{} state = {}, transport={}", 605 bta_dm_search_cb.name_discover_done, 606 fmt::ptr(bta_dm_search_cb.p_btm_inq_info), bta_dm_search_get_state(), 607 transport); 608 609 if (bta_dm_search_cb.p_btm_inq_info) { 610 log::verbose("appl_knows_rem_name {}", 611 bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name); 612 } 613 /** M: Avoid initiate RNR to LE transport. @{ */ 614 if (((bta_dm_search_cb.p_btm_inq_info) && 615 (bta_dm_search_cb.p_btm_inq_info->results.device_type == 616 BT_DEVICE_TYPE_BLE) && 617 #ifndef OPLUS_FEATURE_BT_LE_AUDIO 618 (bta_dm_search_get_state() == BTA_DM_SEARCH_ACTIVE)) || 619 transport == BT_TRANSPORT_LE && 620 interop_match_addr(INTEROP_DISABLE_NAME_REQUEST, 621 &bta_dm_search_cb.peer_bdaddr))) { 622 #else 623 (bta_dm_search_get_state() == BTA_DM_SEARCH_ACTIVE)) || 624 (transport == BT_TRANSPORT_LE && (!is_device_le_audio_capable(remote_bd_addr)))) { 625 #endif /* OPLUS_FEATURE_BT_LE_AUDIO */ 626 /** @} */ 627 /* Do not perform RNR for LE devices at inquiry complete*/ 628 bta_dm_search_cb.name_discover_done = true; 629 } 630 631 #ifdef OPLUS_FEATURE_BT_HS_INQUIRY 632 //[email protected], 2021/03/09 633 if(bta_dm_search_cb.p_btm_inq_info) { 634 bta_dm_search_cb.name_discover_done = oplus_check_remote_device_not_need_rnr( 635 //#ifdef OPLUS_FEATURE_BT_LE_AUDIO 636 //[email protected], add acl exist, if exist to read remote name for BLE 637 remote_bd_addr, btm_cb.btm_inq_vars.inq_num, bta_dm_search_cb.p_btm_inq_info->results.rssi); 638 //#endif /*OPLUS_FEATURE_BT_LE_AUDIO*/ 639 if(!bta_dm_search_cb.name_discover_done) { 640 LOG_VERBOSE("%s rssi: %d ,inq_num: %d", __func__, 641 bta_dm_search_cb.p_btm_inq_info->results.rssi, 642 btm_cb.btm_inq_vars.inq_num); 643 } 644 } 645 #endif /*OPLUS_FEATURE_BT_HS_INQUIRY*/ 646 647 // If we already have the name we can skip getting the name 648 if (BTM_IsRemoteNameKnown(remote_bd_addr, transport) && 649 bluetooth::common::init_flags::sdp_skip_rnr_if_known_is_enabled()) { 650 log::debug( 651 "Security record already known skipping read remote name peer:{}", 652 remote_bd_addr); 653 bta_dm_search_cb.name_discover_done = true; 654 } 655 656 /* if name discovery is not done and application needs remote name */ 657 if ((!bta_dm_search_cb.name_discover_done) && 658 ((bta_dm_search_cb.p_btm_inq_info == NULL) || 659 (bta_dm_search_cb.p_btm_inq_info && 660 (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) { 661 if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, 662 transport)) { 663 BTM_LogHistory(kBtmLogTag, bta_dm_search_cb.peer_bdaddr, 664 "Read remote name", 665 base::StringPrintf("Transport:%s", 666 bt_transport_text(transport).c_str())); 667 return; 668 } else { 669 log::error("Unable to start read remote device name"); 670 } 671 672 /* starting name discovery failed */ 673 bta_dm_search_cb.name_discover_done = true; 674 } 675 676 /* name discovery is done for this device */ 677 if (bta_dm_search_get_state() == BTA_DM_SEARCH_ACTIVE) { 678 // if p_btm_inq_info is nullptr, there is no more inquiry results to 679 // discover name for 680 if (bta_dm_search_cb.p_btm_inq_info) { 681 bta_dm_discover_next_device(); 682 } else { 683 log::info("end of parsing inquiry result"); 684 } 685 } else { 686 log::info("name discovery finished in bad state: {}", 687 bta_dm_state_text(bta_dm_search_get_state())); 688 } 689 } 690 691 /******************************************************************************* 692 * 693 * Function bta_dm_is_search_request_queued 694 * 695 * Description Checks if there is a queued search request 696 * 697 * Returns bool 698 * 699 ******************************************************************************/ 700 bool bta_dm_is_search_request_queued() { 701 if (!com::android::bluetooth::flags:: 702 separate_service_and_device_discovery()) { 703 return bta_dm_disc_legacy::bta_dm_is_search_request_queued(); 704 } 705 return bta_dm_search_cb.p_pending_search != NULL; 706 } 707 708 /******************************************************************************* 709 * 710 * Function bta_dm_queue_search 711 * 712 * Description Queues search command 713 * 714 * Returns void 715 * 716 ******************************************************************************/ 717 static void bta_dm_queue_search(tBTA_DM_API_SEARCH& search) { 718 if (bta_dm_search_cb.p_pending_search) { 719 log::warn("Overwrote previous device discovery inquiry scan request"); 720 } 721 bta_dm_search_cb.p_pending_search.reset(new tBTA_DM_SEARCH_MSG(search)); 722 log::info("Queued device discovery inquiry scan request"); 723 } 724 725 /******************************************************************************* 726 * 727 * Function bta_dm_observe_results_cb 728 * 729 * Description Callback for BLE Observe result 730 * 731 * 732 * Returns void 733 * 734 ******************************************************************************/ 735 static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, 736 const uint8_t* p_eir, uint16_t eir_len) { 737 tBTA_DM_SEARCH result; 738 tBTM_INQ_INFO* p_inq_info; 739 log::verbose("bta_dm_observe_results_cb"); 740 741 result.inq_res.bd_addr = p_inq->remote_bd_addr; 742 result.inq_res.original_bda = p_inq->original_bda; 743 result.inq_res.rssi = p_inq->rssi; 744 result.inq_res.ble_addr_type = p_inq->ble_addr_type; 745 result.inq_res.inq_result_type = p_inq->inq_result_type; 746 result.inq_res.device_type = p_inq->device_type; 747 result.inq_res.flag = p_inq->flag; 748 result.inq_res.ble_evt_type = p_inq->ble_evt_type; 749 result.inq_res.ble_primary_phy = p_inq->ble_primary_phy; 750 result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy; 751 result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid; 752 result.inq_res.ble_tx_power = p_inq->ble_tx_power; 753 result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int; 754 755 /* application will parse EIR to find out remote device name */ 756 result.inq_res.p_eir = const_cast<uint8_t*>(p_eir); 757 result.inq_res.eir_len = eir_len; 758 759 p_inq_info = 760 get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr); 761 if (p_inq_info != NULL) { 762 /* initialize remt_name_not_required to false so that we get the name by 763 * default */ 764 result.inq_res.remt_name_not_required = false; 765 } 766 767 if (p_inq_info) { 768 /* application indicates if it knows the remote name, inside the callback 769 copy that to the inquiry data base*/ 770 if (result.inq_res.remt_name_not_required) 771 p_inq_info->appl_knows_rem_name = true; 772 } 773 } 774 775 /******************************************************************************* 776 * 777 * Function bta_dm_opportunistic_observe_results_cb 778 * 779 * Description Callback for BLE Observe result 780 * 781 * 782 * Returns void 783 * 784 ******************************************************************************/ 785 static void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq, 786 const uint8_t* p_eir, 787 uint16_t eir_len) { 788 tBTA_DM_SEARCH result; 789 tBTM_INQ_INFO* p_inq_info; 790 791 result.inq_res.bd_addr = p_inq->remote_bd_addr; 792 result.inq_res.rssi = p_inq->rssi; 793 result.inq_res.ble_addr_type = p_inq->ble_addr_type; 794 result.inq_res.inq_result_type = p_inq->inq_result_type; 795 result.inq_res.device_type = p_inq->device_type; 796 result.inq_res.flag = p_inq->flag; 797 result.inq_res.ble_evt_type = p_inq->ble_evt_type; 798 result.inq_res.ble_primary_phy = p_inq->ble_primary_phy; 799 result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy; 800 result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid; 801 result.inq_res.ble_tx_power = p_inq->ble_tx_power; 802 result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int; 803 804 /* application will parse EIR to find out remote device name */ 805 result.inq_res.p_eir = const_cast<uint8_t*>(p_eir); 806 result.inq_res.eir_len = eir_len; 807 808 p_inq_info = 809 get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr); 810 if (p_inq_info != NULL) { 811 /* initialize remt_name_not_required to false so that we get the name by 812 * default */ 813 result.inq_res.remt_name_not_required = false; 814 } 815 816 if (bta_dm_search_cb.p_csis_scan_cback) 817 bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_RES_EVT, &result); 818 819 if (p_inq_info) { 820 /* application indicates if it knows the remote name, inside the callback 821 copy that to the inquiry data base*/ 822 if (result.inq_res.remt_name_not_required) 823 p_inq_info->appl_knows_rem_name = true; 824 } 825 } 826 827 /******************************************************************************* 828 * 829 * Function bta_dm_observe_cmpl_cb 830 * 831 * Description Callback for BLE Observe complete 832 * 833 * 834 * Returns void 835 * 836 ******************************************************************************/ 837 static void bta_dm_observe_cmpl_cb(void* p_result) { 838 log::verbose("bta_dm_observe_cmpl_cb"); 839 840 if (bta_dm_search_cb.p_csis_scan_cback) { 841 auto num_resps = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp; 842 tBTA_DM_SEARCH data{.observe_cmpl{.num_resps = num_resps}}; 843 bta_dm_search_cb.p_csis_scan_cback(BTA_DM_OBSERVE_CMPL_EVT, &data); 844 } 845 } 846 847 static void bta_dm_start_scan(uint8_t duration_sec, 848 bool low_latency_scan = false) { 849 tBTM_STATUS status = get_btm_client_interface().ble.BTM_BleObserve( 850 true, duration_sec, bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb, 851 low_latency_scan); 852 853 if (status != BTM_CMD_STARTED) { 854 log::warn("BTM_BleObserve failed. status {}", status); 855 if (bta_dm_search_cb.p_csis_scan_cback) { 856 tBTA_DM_SEARCH data{.observe_cmpl = {.num_resps = 0}}; 857 bta_dm_search_cb.p_csis_scan_cback(BTA_DM_OBSERVE_CMPL_EVT, &data); 858 } 859 } 860 } 861 862 void bta_dm_ble_scan(bool start, uint8_t duration_sec, 863 bool low_latency_scan = false) { 864 if (!start) { 865 if (get_btm_client_interface().ble.BTM_BleObserve( 866 false, 0, NULL, NULL, false) != BTM_CMD_STARTED) { 867 log::warn("Unable to start ble observe"); 868 } 869 return; 870 } 871 872 bta_dm_start_scan(duration_sec, low_latency_scan); 873 } 874 875 void bta_dm_ble_csis_observe(bool observe, tBTA_DM_SEARCH_CBACK* p_cback) { 876 if (!observe) { 877 bta_dm_search_cb.p_csis_scan_cback = NULL; 878 BTM_BleOpportunisticObserve(false, NULL); 879 return; 880 } 881 882 /* Save the callback to be called when a scan results are available */ 883 bta_dm_search_cb.p_csis_scan_cback = p_cback; 884 BTM_BleOpportunisticObserve(true, bta_dm_opportunistic_observe_results_cb); 885 } 886 887 namespace bluetooth { 888 namespace legacy { 889 namespace testing { 890 891 void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p) { 892 ::bta_dm_remname_cback(p); 893 } 894 895 void bta_dm_remote_name_cmpl(const tBTA_DM_REMOTE_NAME& remote_name_msg) { 896 ::bta_dm_remote_name_cmpl(remote_name_msg); 897 } 898 899 } // namespace testing 900 } // namespace legacy 901 } // namespace bluetooth 902 903 namespace { 904 constexpr size_t kSearchStateHistorySize = 50; 905 constexpr char kTimeFormatString[] = "%Y-%m-%d %H:%M:%S"; 906 907 constexpr unsigned MillisPerSecond = 1000; 908 std::string EpochMillisToString(long long time_ms) { 909 time_t time_sec = time_ms / MillisPerSecond; 910 struct tm tm; 911 localtime_r(&time_sec, &tm); 912 std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm); 913 return base::StringPrintf( 914 "%s.%03u", s.c_str(), 915 static_cast<unsigned int>(time_ms % MillisPerSecond)); 916 } 917 918 } // namespace 919 920 struct tSEARCH_STATE_HISTORY { 921 const tBTA_DM_DEVICE_SEARCH_STATE state; 922 const tBTA_DM_DEV_SEARCH_EVT event; 923 std::string ToString() const { 924 return base::StringPrintf("state:%25s event:%s", 925 bta_dm_state_text(state).c_str(), 926 bta_dm_event_text(event).c_str()); 927 } 928 }; 929 930 bluetooth::common::TimestampedCircularBuffer<tSEARCH_STATE_HISTORY> 931 search_state_history_(kSearchStateHistorySize); 932 933 /******************************************************************************* 934 * 935 * Function bta_dm_search_sm_execute 936 * 937 * Description State machine event handling function for DM 938 * 939 * 940 * Returns void 941 * 942 ******************************************************************************/ 943 static void bta_dm_search_sm_execute(tBTA_DM_DEV_SEARCH_EVT event, 944 std::unique_ptr<tBTA_DM_SEARCH_MSG> msg) { 945 log::info("state:{}, event:{}[0x{:x}]", 946 bta_dm_state_text(bta_dm_search_get_state()), 947 bta_dm_event_text(event), event); 948 search_state_history_.Push({ 949 .state = bta_dm_search_get_state(), 950 .event = event, 951 }); 952 953 switch (bta_dm_search_get_state()) { 954 case BTA_DM_SEARCH_IDLE: 955 switch (event) { 956 case BTA_DM_API_SEARCH_EVT: 957 bta_dm_search_set_state(BTA_DM_SEARCH_ACTIVE); 958 log::assert_that(std::holds_alternative<tBTA_DM_API_SEARCH>(*msg), 959 "bad message type: {}", msg->index()); 960 961 bta_dm_search_start(std::get<tBTA_DM_API_SEARCH>(*msg)); 962 break; 963 case BTA_DM_API_SEARCH_CANCEL_EVT: 964 bta_dm_search_clear_queue(); 965 bta_dm_search_cancel_notify(); 966 break; 967 default: 968 log::info("Received unexpected event {}[0x{:x}] in state {}", 969 bta_dm_event_text(event), event, 970 bta_dm_state_text(bta_dm_search_get_state())); 971 } 972 break; 973 case BTA_DM_SEARCH_ACTIVE: 974 switch (event) { 975 case BTA_DM_REMT_NAME_EVT: 976 log::assert_that(std::holds_alternative<tBTA_DM_REMOTE_NAME>(*msg), 977 "bad message type: {}", msg->index()); 978 979 bta_dm_remote_name_cmpl(std::get<tBTA_DM_REMOTE_NAME>(*msg)); 980 break; 981 case BTA_DM_SEARCH_CMPL_EVT: 982 bta_dm_search_cmpl(); 983 break; 984 case BTA_DM_API_SEARCH_CANCEL_EVT: 985 bta_dm_search_clear_queue(); 986 bta_dm_search_set_state(BTA_DM_SEARCH_CANCELLING); 987 bta_dm_search_cancel(); 988 break; 989 default: 990 log::info("Received unexpected event {}[0x{:x}] in state {}", 991 bta_dm_event_text(event), event, 992 bta_dm_state_text(bta_dm_search_get_state())); 993 } 994 break; 995 case BTA_DM_SEARCH_CANCELLING: 996 switch (event) { 997 case BTA_DM_API_SEARCH_EVT: 998 log::assert_that(std::holds_alternative<tBTA_DM_API_SEARCH>(*msg), 999 "bad message type: {}", msg->index()); 1000 1001 bta_dm_queue_search(std::get<tBTA_DM_API_SEARCH>(*msg)); 1002 break; 1003 case BTA_DM_API_SEARCH_CANCEL_EVT: 1004 bta_dm_search_clear_queue(); 1005 bta_dm_search_cancel_notify(); 1006 break; 1007 case BTA_DM_REMT_NAME_EVT: 1008 case BTA_DM_SEARCH_CMPL_EVT: 1009 bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); 1010 bta_dm_search_cancel_notify(); 1011 bta_dm_execute_queued_search_request(); 1012 break; 1013 default: 1014 log::info("Received unexpected event {}[0x{:x}] in state {}", 1015 bta_dm_event_text(event), event, 1016 bta_dm_state_text(bta_dm_search_get_state())); 1017 } 1018 break; 1019 } 1020 } 1021 1022 static void bta_dm_disable_search(void) { 1023 switch (bta_dm_search_get_state()) { 1024 case BTA_DM_SEARCH_IDLE: 1025 break; 1026 case BTA_DM_SEARCH_ACTIVE: 1027 case BTA_DM_SEARCH_CANCELLING: 1028 default: 1029 log::debug( 1030 "Search state machine is not idle so issuing search cancel current " 1031 "state:{}", 1032 bta_dm_state_text(bta_dm_search_get_state())); 1033 bta_dm_search_cancel(); 1034 } 1035 } 1036 1037 void bta_dm_disc_start_device_discovery(tBTA_DM_SEARCH_CBACK* p_cback) { 1038 if (!com::android::bluetooth::flags:: 1039 separate_service_and_device_discovery()) { 1040 bta_dm_disc_legacy::bta_dm_disc_start_device_discovery(p_cback); 1041 return; 1042 } 1043 bta_dm_search_sm_execute(BTA_DM_API_SEARCH_EVT, 1044 std::make_unique<tBTA_DM_SEARCH_MSG>( 1045 tBTA_DM_API_SEARCH{.p_cback = p_cback})); 1046 } 分析一下这段代码的逻辑

分析如下程序有无错误,驱动库使用的是https://github.com/Lora-net/llcc68_driver/tree/v2.3.2。:#include "llcc68.h" #include "llcc68_regs.h" #include "rf.h" #include "delay.h" #include "gpio.h" #include "uart_logger.h" #include <stdint.h> #include <stdbool.h> #include "string.h" const void* context = NULL; // 帧类型定义 typedef enum { CMD_SET_GEAR = 0x01, // 设定档位命令 DATA_OPERATION = 0x02, // 操作数据 HEARTBEAT = 0x03, // 心跳包 ACK_OFFSET = 0x80 // 应答帧偏移 } FrameType; // 协议帧结构 typedef struct { uint8_t frameType; // 帧类型 uint8_t dataLen; // 数据长度 uint8_t data[255]; // 数据 uint16_t crc; // CRC校验 } ProtocolFrame; // 设备状态 typedef struct { uint8_t currentGear; // 当前档位 uint8_t operationData; // 操作数据 bool isOnline; // 在线状态 uint32_t lastHeartbeat; // 最后心跳时间 } DeviceStatus; // 全局状态 DeviceStatus devStatus = {0}; uint8_t uTx_addr=0x00, uRx_addr=0x80; #define RX_BUF_MAX_LEN 64 typedef struct { uint8_t data[RX_BUF_MAX_LEN]; // 接收数据 uint8_t len; // 数据长度 bool has_new_data; // 新数据标志 } RxBuffer; static RxBuffer rx_buf = {0}; // 初始化参数结构体(封装所有可配置项) typedef struct { // 基础配置 uint32_t rf_freq; // 射频频率:470000000UL (470MHz) int8_t tx_power; // 发射功率:0dBm llcc68_reg_mod_t reg_mode; // 电源模式:LDO模式 llcc68_standby_cfg_t standby_mode; // 待机模式:STDBY_RC(低功耗) // 中断配置(DIO1映射接收相关中断) llcc68_irq_mask_t irq_mask; // 使能的中断:RX_DONE/RX_TIMEOUT等 uint16_t dio1_irq_mask; // DIO1映射的中断:接收相关 uint16_t dio2_irq_mask; // DIO2:RF开关(无需中断映射) uint16_t dio3_irq_mask; // DIO3:不使用(掩码0) // LoRa模式参数(低速率低辐射配置) struct { llcc68_lora_sf_t sf; // 扩频因子:SF11(低速率) llcc68_lora_bw_t bw; // 带宽:125kHz(低辐射) llcc68_lora_cr_t cr; // 编码率:4/5(可靠性平衡) bool ldro; // 低速率优化:使能 } lora; // FSK模式参数(低速率低辐射配置) struct { uint32_t br; // 比特率:600bps(低速率) uint32_t fdev; // 频偏:300Hz(窄带) llcc68_gfsk_bw_t bw; // 带宽:4.8kHz(低辐射) llcc68_gfsk_pulse_shape_t pulse; // 脉冲形状:GFSK_BT05 } fsk; } rf_init_params_t; // 默认参数配置(符合需求的初始化值) static const rf_init_params_t default_params = { .rf_freq = 470000000UL, .tx_power = 0, .reg_mode = LLCC68_REG_MODE_LDO, .standby_mode = LLCC68_STANDBY_CFG_RC, // DIO1仅映射接收相关中断:接收完成/超时/CRC错误 .irq_mask = LLCC68_IRQ_RX_DONE | LLCC68_IRQ_TIMEOUT | LLCC68_IRQ_CRC_ERROR, .dio1_irq_mask = LLCC68_IRQ_RX_DONE | LLCC68_IRQ_TIMEOUT | LLCC68_IRQ_CRC_ERROR, .dio2_irq_mask = 0, // DIO2作为RF开关,无需中断 .dio3_irq_mask = 0, // DIO3不使用 // LoRa低速率配置:SF9 + 125kHz .lora = { .sf = LLCC68_LORA_SF9, .bw = LLCC68_LORA_BW_125, .cr = LLCC68_LORA_CR_4_5, .ldro = false //仅在sf>9时 可为true }, // FSK低速率配置:600bps + 4.8kHz带宽 .fsk = { .br = 600, .fdev = 300, .bw = LLCC68_GFSK_BW_4800, .pulse = LLCC68_GFSK_PULSE_SHAPE_BT_05 } }; static rf_init_status_t rf_calibrate( rf_init_params_t *params) { llcc68_status_t status =RF_INIT_SUCCESS; // 全量校准 status = llcc68_cal(context, LLCC68_CAL_ALL); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_CALIBRATION; // 图像校准(针对470MHz频段优化,范围覆盖470-510MHz) status = llcc68_cal_img_in_mhz(context, 470, 510); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_CALIBRATION; return status; } /** * @brief 初始化LLCC68射频芯片(完整优化版) * @param mode 选择LoRa或FSK模式 * @return 初始化状态(成功/具体错误) * * 设计要点: * 1. 严格遵循手册命令顺序(包类型→调制参数→包参数) * 2. 频率设置在校准前完成(手册9.2要求) * 3. 智能LDRO配置(根据SF值自动启用) * 4. 增强功能集成(TCXO/寄存器保留/钳位保护) */ rf_init_status_t rf_init(rf_mode_t mode) { llcc68_status_t status; const rf_init_params_t* params = &default_params; // 使用预定义参数 /*--- 阶段1:芯片基础初始化 ---*/ // 硬件复位(手册9.1.5要求至少5ms延迟) status = llcc68_reset(context); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_RESET; // delay_ms(5); // 依赖硬件抽象层实现的毫秒延时 // // 从睡眠模式唤醒芯片 // status = llcc68_wakeup(context); // if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_RESET; // 配置待机模式(低功耗RC振荡器模式) status = llcc68_set_standby(context, params->standby_mode); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_STANDBY; // 设置电源调节模式(LDO模式提供更稳定电压) status = llcc68_set_reg_mode(context, params->reg_mode); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_REGULATOR; /*--- 阶段2:射频频率与校准 ---*/ // 设置频率 status = llcc68_set_rf_freq(context, params->rf_freq); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_FREQ; status = rf_calibrate( params); if(status != RF_INIT_SUCCESS) return status; /*--- 阶段3:引脚与中断配置 ---*/ // 配置DIO2为RF开关控制(Tx=高电平,Rx=低电平) status = llcc68_set_dio2_as_rf_sw_ctrl(context, true); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_DIO_CONFIG; // 配置中断映射: // - DIO1: 仅接收相关中断(完成/超时/CRC错误) // - DIO2/DIO3: 禁用中断功能 status = llcc68_set_dio_irq_params(context, params->irq_mask, // 使能的中断类型 params->dio1_irq_mask, // DIO1映射 0, // DIO2无中断 0); // DIO3无中断 if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_IRQ_MAPPING; // 清除所有挂起的中断状态 status = llcc68_clear_irq_status(context, LLCC68_IRQ_ALL); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_IRQ_MAPPING; /*--- 阶段4:功率放大器配置 ---*/ // PA参数设计(0dBm输出目标,2dB余量设计) const llcc68_pa_cfg_params_t pa_cfg = { .pa_duty_cycle = 0x04, // 25%占空比(低功耗优化) .hp_max = 0x02, // +2dBm最大限制(提供设计余量) .device_sel = 0x00, // 默认设备选择 .pa_lut = 0x01 // 默认PA查找表 }; status = llcc68_set_pa_cfg(context, &pa_cfg); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_PA_CONFIG; /*--- 阶段5:无线电模式配置 ---*/ if (mode == LORA) { /*--- LoRa模式配置 ---*/ // 5.1 设置包类型(必须第一步) status = llcc68_set_pkt_type(context, LLCC68_PKT_TYPE_LORA); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_MOD_PARAMS; // 5.2 调制参数配置(手册14.4要求的第二步) bool ldro_needed = (params->lora.sf >= LLCC68_LORA_SF11); // SF11+需LDRO const llcc68_mod_params_lora_t lora_mod = { .sf = params->lora.sf, // SF9(125kHz带宽时速率约980bps) .bw = params->lora.bw, // 125kHz带宽(平衡距离与抗干扰) .cr = params->lora.cr, // 4/5编码率(高编码效率) .ldro = ldro_needed // 自动LDRO配置 }; status = llcc68_set_lora_mod_params(context, &lora_mod); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_MOD_PARAMS; // 5.3 包参数配置(手册14.4要求的第三步) const llcc68_pkt_params_lora_t lora_pkt = { .preamble_len_in_symb = 12, // 12符号前导码(快速同步) .header_type = LLCC68_LORA_PKT_EXPLICIT, // 显式包头(含长度信息) .pld_len_in_bytes = 255, // 最大负载长度 .crc_is_on = true, // CRC校验使能(提高可靠性) .invert_iq_is_on = false // 标准IQ极性(兼容常规设备) }; status = llcc68_set_lora_pkt_params(context, &lora_pkt); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_PKT_PARAMS; } else { /*--- FSK模式配置 ---*/ // 5.1 设置包类型(必须第一步) status = llcc68_set_pkt_type(context, LLCC68_PKT_TYPE_GFSK); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_MOD_PARAMS; // 5.2 调制参数配置(手册14.4要求的第二步) const llcc68_mod_params_gfsk_t fsk_mod = { .br_in_bps = params->fsk.br, // 600bps(超低速率) .fdev_in_hz = params->fsk.fdev, // 300Hz频偏(窄带传输) .pulse_shape = params->fsk.pulse, // BT=0.5高斯滤波(降低带外辐射) .bw_dsb_param = params->fsk.bw // 4.8kHz带宽(最小化干扰) }; status = llcc68_set_gfsk_mod_params(context, &fsk_mod); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_MOD_PARAMS; // 5.3 包参数配置(手册14.4要求的第三步) const llcc68_pkt_params_gfsk_t fsk_pkt = { .preamble_len_in_bits = 32, // 32位前导码(提高检测可靠性) .preamble_detector = LLCC68_GFSK_PREAMBLE_DETECTOR_MIN_8BITS, // 8位检测阈值 .sync_word_len_in_bits = 16, // 16位同步字 .address_filtering = LLCC68_GFSK_ADDRESS_FILTERING_DISABLE, // 禁用地址过滤 .header_type = LLCC68_GFSK_PKT_VAR_LEN, // 可变长度包 .pld_len_in_bytes = 255, // 最大负载长度 .crc_type = LLCC68_GFSK_CRC_2_BYTES, // 2字节CRC(强校验) .dc_free = LLCC68_GFSK_DC_FREE_WHITENING // 白化处理(降低DC偏移) }; status = llcc68_set_gfsk_pkt_params(context, &fsk_pkt); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_PKT_PARAMS; // 5.4 同步字独立配置(0xAA55提高抗噪性) const uint8_t sync_word[2] = {0xAA, 0x55}; // 高抗噪同步模式 status = llcc68_set_gfsk_sync_word(context, sync_word, 2); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_PKT_PARAMS; } // 6. 发射参数统一配置(0dBm输出,10μs斜坡时间) status = llcc68_set_tx_params(context, params->tx_power, LLCC68_RAMP_10_US); if (status != LLCC68_STATUS_OK) return RF_INIT_ERR_PA_CONFIG; // 设置缓冲区地址 llcc68_set_buffer_base_address(context, uTx_addr, uRx_addr); /*--- 阶段7:增强功能配置 ---*/ // 7.1 TCXO控制(稳定时钟源,500ms启动时间) // status = llcc68_set_dio3_as_tcxo_ctrl(context, LLCC68_TCXO_CTRL_1_8V, 500); // 7.2 寄存器保留列表(睡眠模式保持关键寄存器) const uint16_t retain_regs[] = { LLCC68_REG_RXGAIN, // RX增益配置 LLCC68_REG_TX_MODULATION // TX调制参数 }; status = llcc68_add_registers_to_retention_list(context, retain_regs, 2); // 7.3 发射钳位保护(防静电/过压损坏) status = llcc68_cfg_tx_clamp(context); /*--- 最终状态:返回待机模式 ---*/ if (llcc68_set_standby(context, params->standby_mode) == LLCC68_STATUS_OK) log_printf(LOG_LEVEL_INFO, "RF初始化成功"); } // CRC16计算 uint16_t crc16(const uint8_t *data, uint8_t len) { uint16_t crc = 0xFFFF; for (uint8_t i = 0; i < len; i++) { crc ^= (uint16_t)data[i]; for (uint8_t j = 0; j < 8; j++) { if (crc & 0x0001) { crc >>= 1; crc ^= 0xA001; } else { crc >>= 1; } } } return crc; } // 打包协议帧 uint8_t packFrame(ProtocolFrame *frame, FrameType type, const uint8_t *data, uint8_t len) { if (len > 255) return 0; frame->frameType = type; frame->dataLen = len; memcpy(frame->data, data, len); // 计算CRC(不包含CRC字段本身) uint8_t crcData[257]; crcData[0] = frame->frameType; crcData[1] = frame->dataLen; memcpy(&crcData[2], frame->data, len); frame->crc = crc16(crcData, len + 2); return len + 4; // 总长度:类型(1)+长度(1)+数据(len)+CRC(2) } // 解析协议帧,返回0表示成功 uint8_t unpackFrame(ProtocolFrame *frame, const uint8_t *data, uint8_t len) { if (len < 4) return 1; // 最小帧长度检查 frame->frameType = data[0]; frame->dataLen = data[1]; // 检查长度合法性 if (frame->dataLen + 4 != len) return 2; memcpy(frame->data, &data[2], frame->dataLen); frame->crc = (data[frame->dataLen + 2] << 8) | data[frame->dataLen + 3]; // CRC校验 uint8_t crcData[257]; crcData[0] = frame->frameType; crcData[1] = frame->dataLen; memcpy(&crcData[2], frame->data, frame->dataLen); uint16_t calcCrc = crc16(crcData, frame->dataLen + 2); return (calcCrc == frame->crc) ? 0 : 3; } // 发送协议帧 llcc68_status_t sendProtocolFrame( ProtocolFrame *frame, bool isLoRa) { // 转换协议帧为字节流 uint8_t txBuffer[260]; txBuffer[0] = frame->frameType; txBuffer[1] = frame->dataLen; memcpy(&txBuffer[2], frame->data, frame->dataLen); txBuffer[frame->dataLen + 2] = (frame->crc >> 8) & 0xFF; txBuffer[frame->dataLen + 3] = frame->crc & 0xFF; uint8_t txLen = frame->dataLen + 4; // 写入发送数据 llcc68_write_buffer(context, 0x00, txBuffer, txLen); return llcc68_set_tx(context, 1000); } // 处理接收到的帧 void processReceivedFrame( ProtocolFrame *frame) { ProtocolFrame ackFrame; uint8_t ackData = 0x00; // 默认成功 switch (frame->frameType) { case CMD_SET_GEAR: // 处理档位设置命令 if (frame->dataLen == 1) { devStatus.currentGear = frame->data[0]; // 确保档位在有效范围内 if (devStatus.currentGear > 0x0F) { devStatus.currentGear = 0x0F; ackData = 0x02; // 档位值修正 } } else { ackData = 0x01; // 数据长度错误 } // 发送应答 packFrame(&ackFrame, frame->frameType + ACK_OFFSET, &ackData, 1); sendProtocolFrame( &ackFrame, true); break; case DATA_OPERATION: // 处理操作数据 if (frame->dataLen == 1) { devStatus.operationData = frame->data[0]; // 这里可以添加数据处理逻辑 } else { ackData = 0x01; // 数据长度错误 } // 发送应答 packFrame(&ackFrame, frame->frameType + ACK_OFFSET, &ackData, 1); sendProtocolFrame( &ackFrame, true); break; case HEARTBEAT: // 处理心跳包 devStatus.isOnline = true; // 可以在这里更新最后心跳时间 // 心跳包通常不需要应答,除非有特殊需求 break; default: // 未知帧类型 break; } } // 接收中断处理函数 void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin) { if(GPIO_Pin == RF_IRQ_Pin) { llcc68_irq_mask_t irqMask; llcc68_get_and_clear_irq_status(context, &irqMask); log_printf(LOG_LEVEL_INFO, "一号板 rf irq"); // 处理接收完成中断 if (irqMask & LLCC68_IRQ_RX_DONE) { llcc68_rx_buffer_status_t rxBufferStatus; llcc68_get_rx_buffer_status(context, &rxBufferStatus); if (rxBufferStatus.pld_len_in_bytes > 0) { llcc68_read_buffer(context, rxBufferStatus.buffer_start_pointer, rx_buf.data, rxBufferStatus.pld_len_in_bytes); rx_buf.len = rxBufferStatus.pld_len_in_bytes; rx_buf.has_new_data = true; // 设置新数据标志 } // 重新进入接收模式 llcc68_set_rx(context, 0); // 连续接收 } } } // 发送心跳包 void sendHeartbeat( void) { ProtocolFrame frame; uint8_t status = 0x00; // 0x00表示正常 packFrame(&frame, HEARTBEAT, &status, 1); sendProtocolFrame( &frame, true); } // 设置档位并发送 void setGearAndSend(uint8_t gear) { log_printf(LOG_LEVEL_INFO, "一号板 rf send"); ProtocolFrame frame; packFrame(&frame, CMD_SET_GEAR, &gear, 1); sendProtocolFrame( &frame, true); } // 发送操作数据 void sendOperationData( uint8_t data) { ProtocolFrame frame; packFrame(&frame, DATA_OPERATION, &data, 1); sendProtocolFrame( &frame, true); } void process_new_rx_data(void) { if (rx_buf.has_new_data) { // 1. 临界区保护:复制数据到本地缓冲区,避免被中断覆盖 uint8_t local_data[RX_BUF_MAX_LEN]; uint8_t local_len; memcpy(local_data, rx_buf.data, rx_buf.len); local_len = rx_buf.len; rx_buf.has_new_data = false; // 清除标志 // 2. 按协议解析数据(原unpackFrame逻辑) ProtocolFrame frame; if (unpackFrame(&frame, local_data, local_len) == 0) { // 3. 处理解析后的帧(原processReceivedFrame逻辑) processReceivedFrame(&frame); } } }

static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, 548 bt_bond_state_t state) { 549 btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_BOND_STATE_CHANGED, state); 550 551 if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING)) { 552 // Cross key pairing so send callback for static address 553 if (!pairing_cb.static_bdaddr.IsEmpty()) { 554 GetInterfaceToProfiles()->events->invoke_bond_state_changed_cb( 555 status, bd_addr, state, pairing_cb.fail_reason); 556 } 557 return; 558 } 559 560 if (pairing_cb.bond_type == tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY) { 561 state = BT_BOND_STATE_NONE; 562 } 563 564 LOG_INFO( 565 "Bond state changed to state=%d [0:none, 1:bonding, 2:bonded]," 566 " prev_state=%d, sdp_attempts = %d", 567 state, pairing_cb.state, pairing_cb.sdp_attempts); 568 569 if (state == BT_BOND_STATE_NONE) { 570 forget_device_from_metric_id_allocator(bd_addr); 571 572 if (bluetooth::common::init_flags:: 573 pbap_pse_dynamic_version_upgrade_is_enabled()) { 574 if (btif_storage_is_pce_version_102(bd_addr)) { 575 update_pce_entry_to_interop_database(bd_addr); 576 } 577 } 578 } else if (state == BT_BOND_STATE_BONDED) { 579 allocate_metric_id_from_metric_id_allocator(bd_addr); 580 if (!save_metric_id_from_metric_id_allocator(bd_addr)) { 581 LOG(FATAL) << __func__ << ": Fail to save metric id for device " 582 << bd_addr; 583 } 584 } 585 GetInterfaceToProfiles()->events->invoke_bond_state_changed_cb( 586 status, bd_addr, state, pairing_cb.fail_reason); 587 588 int dev_type; 589 if (!btif_get_device_type(bd_addr, &dev_type)) { 590 dev_type = BT_DEVICE_TYPE_BREDR; 591 } 592 593 if ((state == BT_BOND_STATE_NONE) && (pairing_cb.bd_addr != bd_addr) 594 && is_bonding_or_sdp()) { 595 LOG_WARN("Ignoring bond state changed for unexpected device: %s pairing: %s", 596 ADDRESS_TO_LOGGABLE_CSTR(bd_addr), ADDRESS_TO_LOGGABLE_CSTR(pairing_cb.bd_addr)); 597 return; 598 } 599 600 if (state == BT_BOND_STATE_BONDING || 601 (state == BT_BOND_STATE_BONDED && 602 (pairing_cb.sdp_attempts > 0 || 603 pairing_cb.gatt_over_le == 604 btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED))) { 605 // Save state for the device is bonding or SDP or GATT over LE discovery 606 pairing_cb.state = state; 607 pairing_cb.bd_addr = bd_addr; 608 } else { 609 LOG_INFO("clearing btif pairing_cb"); 610 pairing_cb = {}; 611 } 612 } 613 代码分析

/* * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ /**************************************************************************** * This is a demo for bluetooth config wifi connection to ap. You can config ESP32 to connect a softap * or config ESP32 as a softap to be connected by other device. APP can be downloaded from github * android source code: https://github.com/EspressifApp/EspBlufi * iOS source code: https://github.com/EspressifApp/EspBlufiForiOS ****************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_mac.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_sntp.h" #include "time.h" #include "esp_log.h" #include "nvs_flash.h" #if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED #include "esp_bt.h" #endif #include "esp_blufi_api.h" #include "blufi_example.h" #include "esp_blufi.h" #include "wifi-bt.h" #include "esp_wifi.h" #include "esp_bt_main.h" #include "esp_bt_device.h" #define EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY CONFIG_EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY #define EXAMPLE_INVALID_REASON 255 #define EXAMPLE_INVALID_RSSI -128 #if CONFIG_ESP_WIFI_AUTH_OPEN #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN #elif CONFIG_ESP_WIFI_AUTH_WEP #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP #elif CONFIG_ESP_WIFI_AUTH_WPA_PSK #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK #elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK #elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK #elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK #elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK #elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK #endif #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param); #define WIFI_LIST_NUM 10 static wifi_config_t sta_config; static wifi_config_t ap_config; /* FreeRTOS event group to signal when we are connected & ready to make a request */ static EventGroupHandle_t wifi_event_group; /* The event group allows multiple bits for each event, but we only care about one event - are we connected to the AP with an IP? */ const int CONNECTED_BIT = BIT0; static uint8_t example_wifi_retry = 0; TaskHandle_t scan_task_handle = NULL; /* store the station info for send back to phone */ static bool gl_sta_connected = false; static bool gl_sta_got_ip = false; static bool ble_is_connected = false; static uint8_t gl_sta_bssid[6]; static uint8_t gl_sta_ssid[32]; static int gl_sta_ssid_len; static wifi_sta_list_t gl_sta_list; static bool gl_sta_is_connecting = false; static esp_blufi_extra_info_t gl_sta_conn_info; static void example_record_wifi_conn_info(int rssi, uint8_t reason) { memset(&gl_sta_conn_info, 0, sizeof(esp_blufi_extra_info_t)); if (gl_sta_is_connecting) { gl_sta_conn_info.sta_max_conn_retry_set = true; gl_sta_conn_info.sta_max_conn_retry = EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY; } else { gl_sta_conn_info.sta_conn_rssi_set = true; gl_sta_conn_info.sta_conn_rssi = rssi; gl_sta_conn_info.sta_conn_end_reason_set = true; gl_sta_conn_info.sta_conn_end_reason = reason; } } static void example_wifi_connect(void) { example_wifi_retry = 0; gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK); example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON); } static bool example_wifi_reconnect(void) { bool ret; if (gl_sta_is_connecting && example_wifi_retry++ < EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY) { BLUFI_INFO("BLUFI WiFi starts reconnection\n"); gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK); example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON); ret = true; } else { ret = false; } return ret; } static int softap_get_current_connection_number(void) { esp_err_t ret; ret = esp_wifi_ap_get_sta_list(&gl_sta_list); if (ret == ESP_OK) { return gl_sta_list.num; } return 0; } static void ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { wifi_mode_t mode; switch (event_id) { case IP_EVENT_STA_GOT_IP: { esp_blufi_extra_info_t info; xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); esp_wifi_get_mode(&mode); memset(&info, 0, sizeof(esp_blufi_extra_info_t)); memcpy(info.sta_bssid, gl_sta_bssid, 6); info.sta_bssid_set = true; info.sta_ssid = gl_sta_ssid; info.sta_ssid_len = gl_sta_ssid_len; gl_sta_got_ip = true; if (ble_is_connected == true) { esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, softap_get_current_connection_number(), &info); } else { BLUFI_INFO("BLUFI BLE is not connected yet\n"); } break; } default: break; } return; } static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { wifi_event_sta_connected_t *event; wifi_event_sta_disconnected_t *disconnected_event; wifi_mode_t mode; switch (event_id) { case WIFI_EVENT_STA_START: example_wifi_connect(); break; case WIFI_EVENT_STA_CONNECTED: gl_sta_connected = true; gl_sta_is_connecting = false; net_status = true; event = (wifi_event_sta_connected_t*) event_data; memcpy(gl_sta_bssid, event->bssid, 6); memcpy(gl_sta_ssid, event->ssid, event->ssid_len); gl_sta_ssid_len = event->ssid_len; break; case WIFI_EVENT_STA_DISCONNECTED: /* Only handle reconnection during connecting */ if (gl_sta_connected == false && example_wifi_reconnect() == false) { gl_sta_is_connecting = false; disconnected_event = (wifi_event_sta_disconnected_t*) event_data; example_record_wifi_conn_info(disconnected_event->rssi, disconnected_event->reason); } /* This is a workaround as ESP32 WiFi libs don't currently auto-reassociate. */ gl_sta_connected = false; gl_sta_got_ip = false; memset(gl_sta_ssid, 0, 32); memset(gl_sta_bssid, 0, 6); gl_sta_ssid_len = 0; xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); break; case WIFI_EVENT_AP_START: esp_wifi_get_mode(&mode); /* TODO: get config or information of softap, then set to report extra_info */ if (ble_is_connected == true) { if (gl_sta_connected) { esp_blufi_extra_info_t info; memset(&info, 0, sizeof(esp_blufi_extra_info_t)); memcpy(info.sta_bssid, gl_sta_bssid, 6); info.sta_bssid_set = true; info.sta_ssid = gl_sta_ssid; info.sta_ssid_len = gl_sta_ssid_len; esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info); } else if (gl_sta_is_connecting) { esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info); } else { esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info); } } else { BLUFI_INFO("BLUFI BLE is not connected yet\n"); } break; case WIFI_EVENT_SCAN_DONE: { uint16_t apCount = 0; esp_wifi_scan_get_ap_num(&apCount); if (apCount == 0) { BLUFI_INFO("Nothing AP found"); break; } wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount); if (!ap_list) { BLUFI_ERROR("malloc error, ap_list is NULL"); esp_wifi_clear_ap_list(); break; } ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list)); esp_blufi_ap_record_t * blufi_ap_list = (esp_blufi_ap_record_t *)malloc(apCount * sizeof(esp_blufi_ap_record_t)); if (!blufi_ap_list) { if (ap_list) { free(ap_list); } BLUFI_ERROR("malloc error, blufi_ap_list is NULL"); break; } for (int i = 0; i < apCount; ++i) { blufi_ap_list[i].rssi = ap_list[i].rssi; memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid)); } if (ble_is_connected == true) { esp_blufi_send_wifi_list(apCount, blufi_ap_list); } else { BLUFI_INFO("BLUFI BLE is not connected yet\n"); } esp_wifi_scan_stop(); free(ap_list); free(blufi_ap_list); break; } case WIFI_EVENT_AP_STACONNECTED: { wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data; BLUFI_INFO("station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid); break; } case WIFI_EVENT_AP_STADISCONNECTED: { wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; BLUFI_INFO("station "MACSTR" leave, AID=%d, reason=%d", MAC2STR(event->mac), event->aid, event->reason); break; } default: break; } return; } static void initialise_wifi(void) { ESP_ERROR_CHECK(esp_netif_init()); wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta(); assert(sta_netif); esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap(); assert(ap_netif); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL)); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON); ESP_ERROR_CHECK( esp_wifi_start() ); } static esp_blufi_callbacks_t example_callbacks = { .event_cb = example_event_callback, .negotiate_data_handler = blufi_dh_negotiate_data_handler, .encrypt_func = blufi_aes_encrypt, .decrypt_func = blufi_aes_decrypt, .checksum_func = blufi_crc_checksum, }; // 获取当前STA模式的IP地址 static char* get_sta_ip_string(void) { static char ip_str[16] = {0}; esp_netif_ip_info_t ip_info; esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); if (netif && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) { snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&ip_info.ip)); return ip_str; } return "0.0.0.0"; } static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param) { /* actually, should post to blufi_task handle the procedure, * now, as a example, we do it more simply */ switch (event) { case ESP_BLUFI_EVENT_INIT_FINISH: BLUFI_INFO("BLUFI init finish\n"); esp_blufi_adv_start(); break; case ESP_BLUFI_EVENT_DEINIT_FINISH: BLUFI_INFO("BLUFI deinit finish\n"); break; case ESP_BLUFI_EVENT_BLE_CONNECT: BLUFI_INFO("BLUFI ble connect\n"); ble_is_connected = true; esp_blufi_adv_stop(); blufi_security_init(); break; case ESP_BLUFI_EVENT_BLE_DISCONNECT: BLUFI_INFO("BLUFI ble disconnect\n"); ble_is_connected = false; blufi_security_deinit(); esp_blufi_adv_start(); break; case ESP_BLUFI_EVENT_SET_WIFI_OPMODE: BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode); ESP_ERROR_CHECK( esp_wifi_set_mode(param->wifi_mode.op_mode) ); break; case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP: BLUFI_INFO("BLUFI request wifi connect to AP\n"); /* there is no wifi callback when the device has already connected to this wifi so disconnect wifi before connection. */ esp_wifi_disconnect(); example_wifi_connect(); break; case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP: BLUFI_INFO("BLUFI request wifi disconnect from AP\n"); esp_wifi_disconnect(); break; case ESP_BLUFI_EVENT_REPORT_ERROR: BLUFI_ERROR("BLUFI report error, error code %d\n", param->report_error.state); esp_blufi_send_error_info(param->report_error.state); break; case ESP_BLUFI_EVENT_GET_WIFI_STATUS: { wifi_mode_t mode; esp_blufi_extra_info_t info; esp_wifi_get_mode(&mode); if (gl_sta_connected) { memset(&info, 0, sizeof(esp_blufi_extra_info_t)); memcpy(info.sta_bssid, gl_sta_bssid, 6); info.sta_bssid_set = true; info.sta_ssid = gl_sta_ssid; info.sta_ssid_len = gl_sta_ssid_len; esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info); // 新增IP地址上报 if (gl_sta_got_ip) { const char *ip = get_sta_ip_string(); // 格式: "IP:192.168.1.100" char ip_report[20]; snprintf(ip_report, sizeof(ip_report), "IP:%s", ip); esp_blufi_send_custom_data((uint8_t*)ip_report, strlen(ip_report)); BLUFI_INFO("Reported IP: %s\n", ip); } } else if (gl_sta_is_connecting) { esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info); } else { net_status = false; esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info); } BLUFI_INFO("BLUFI get wifi status from AP\n"); break; } case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE: BLUFI_INFO("blufi close a gatt connection"); esp_blufi_disconnect(); break; case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA: /* TODO */ break; case ESP_BLUFI_EVENT_RECV_STA_BSSID: memcpy(sta_config.sta.bssid, param->sta_bssid.bssid, 6); sta_config.sta.bssid_set = 1; esp_wifi_set_config(WIFI_IF_STA, &sta_config); BLUFI_INFO("Recv STA BSSID %s\n", sta_config.sta.ssid); break; case ESP_BLUFI_EVENT_RECV_STA_SSID: if (param->sta_ssid.ssid_len >= sizeof(sta_config.sta.ssid)/sizeof(sta_config.sta.ssid[0])) { esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR); BLUFI_INFO("Invalid STA SSID\n"); break; } strncpy((char *)sta_config.sta.ssid, (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len); sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0'; esp_wifi_set_config(WIFI_IF_STA, &sta_config); BLUFI_INFO("Recv STA SSID %s\n", sta_config.sta.ssid); break; case ESP_BLUFI_EVENT_RECV_STA_PASSWD: if (param->sta_passwd.passwd_len >= sizeof(sta_config.sta.password)/sizeof(sta_config.sta.password[0])) { esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR); BLUFI_INFO("Invalid STA PASSWORD\n"); break; } strncpy((char *)sta_config.sta.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len); sta_config.sta.password[param->sta_passwd.passwd_len] = '\0'; sta_config.sta.threshold.authmode = EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD; esp_wifi_set_config(WIFI_IF_STA, &sta_config); BLUFI_INFO("Recv STA PASSWORD %s\n", sta_config.sta.password); break; case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID: if (param->softap_ssid.ssid_len >= sizeof(ap_config.ap.ssid)/sizeof(ap_config.ap.ssid[0])) { esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR); BLUFI_INFO("Invalid SOFTAP SSID\n"); break; } strncpy((char *)ap_config.ap.ssid, (char *)param->softap_ssid.ssid, param->softap_ssid.ssid_len); ap_config.ap.ssid[param->softap_ssid.ssid_len] = '\0'; ap_config.ap.ssid_len = param->softap_ssid.ssid_len; esp_wifi_set_config(WIFI_IF_AP, &ap_config); BLUFI_INFO("Recv SOFTAP SSID %s, ssid len %d\n", ap_config.ap.ssid, ap_config.ap.ssid_len); break; case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD: if (param->softap_passwd.passwd_len >= sizeof(ap_config.ap.password)/sizeof(ap_config.ap.password[0])) { esp_blufi_send_error_info(ESP_BLUFI_DATA_FORMAT_ERROR); BLUFI_INFO("Invalid SOFTAP PASSWD\n"); break; } strncpy((char *)ap_config.ap.password, (char *)param->softap_passwd.passwd, param->softap_passwd.passwd_len); ap_config.ap.password[param->softap_passwd.passwd_len] = '\0'; esp_wifi_set_config(WIFI_IF_AP, &ap_config); BLUFI_INFO("Recv SOFTAP PASSWORD %s len = %d\n", ap_config.ap.password, param->softap_passwd.passwd_len); break; case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM: if (param->softap_max_conn_num.max_conn_num > 4) { return; } ap_config.ap.max_connection = param->softap_max_conn_num.max_conn_num; esp_wifi_set_config(WIFI_IF_AP, &ap_config); BLUFI_INFO("Recv SOFTAP MAX CONN NUM %d\n", ap_config.ap.max_connection); break; case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE: if (param->softap_auth_mode.auth_mode >= WIFI_AUTH_MAX) { return; } ap_config.ap.authmode = param->softap_auth_mode.auth_mode; esp_wifi_set_config(WIFI_IF_AP, &ap_config); BLUFI_INFO("Recv SOFTAP AUTH MODE %d\n", ap_config.ap.authmode); break; case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL: if (param->softap_channel.channel > 13) { return; } ap_config.ap.channel = param->softap_channel.channel; esp_wifi_set_config(WIFI_IF_AP, &ap_config); BLUFI_INFO("Recv SOFTAP CHANNEL %d\n", ap_config.ap.channel); break; case ESP_BLUFI_EVENT_GET_WIFI_LIST:{ wifi_scan_config_t scanConf = { .ssid = NULL, .bssid = NULL, .channel = 0, .show_hidden = false }; esp_err_t ret = esp_wifi_scan_start(&scanConf, true); ESP_LOGI("esp-wifi", "start wifi scan"); if (ret != ESP_OK) { esp_blufi_send_error_info(ESP_BLUFI_WIFI_SCAN_FAIL); } break; } case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA: BLUFI_INFO("Recv Custom Data %" PRIu32 "\n", param->custom_data.data_len); ESP_LOG_BUFFER_HEX("Custom Data", param->custom_data.data, param->custom_data.data_len); break; case ESP_BLUFI_EVENT_RECV_USERNAME: /* Not handle currently */ break; case ESP_BLUFI_EVENT_RECV_CA_CERT: /* Not handle currently */ break; case ESP_BLUFI_EVENT_RECV_CLIENT_CERT: /* Not handle currently */ break; case ESP_BLUFI_EVENT_RECV_SERVER_CERT: /* Not handle currently */ break; case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY: /* Not handle currently */ break;; case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY: /* Not handle currently */ break; default: break; } } void blufi_wifi_config_init(void) { esp_err_t ret; // Initialize NVS ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // Initialize WiFi initialise_wifi(); // Initialize BLUFI controller and callback functions #if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED ret = esp_blufi_controller_init(); if (ret) { BLUFI_ERROR("%s BLUFI controller init failed: %s\n", __func__, esp_err_to_name(ret)); return; } #endif ret = esp_blufi_host_and_cb_init(&example_callbacks); if (ret) { BLUFI_ERROR("%s initialise failed: %s\n", __func__, esp_err_to_name(ret)); return; } BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version()); } void get_wifi_ip_adress(void) { // 获取 IP 地址 esp_netif_t* esp_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); esp_netif_ip_info_t ip_info; if (esp_netif_get_ip_info(esp_netif, &ip_info) == ESP_OK) { ESP_LOGI("wifi_info", "IP Address: " IPSTR, IP2STR(&ip_info.ip)); ESP_LOGI("wifi_info", "Netmask: " IPSTR, IP2STR(&ip_info.netmask)); ESP_LOGI("wifi_info", "Gateway: " IPSTR, IP2STR(&ip_info.gw)); } else { ESP_LOGE("wifi_info", "Failed to get IP info"); } } // 初始化 NTP 客户端并同步时间 bool initialize_sntp_and_sync_time(void) { ESP_LOGI("app_main", "Initializing SNTP"); esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); esp_sntp_setservername(0, "pool.ntp.org"); esp_sntp_set_time_sync_notification_cb(NULL); esp_sntp_init(); // 设置时区为东八区(北京时间) setenv("TZ", "Asia/Shanghai", 1); tzset(); // 等待时间同步 int retry = 0; const int retry_count = 10; while (esp_sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) { ESP_LOGI("NTP", "Waiting for time sync... %d", retry); vTaskDelay(pdMS_TO_TICKS(750)); } if (retry == retry_count) { ESP_LOGE("NTP", "Could not sync time with NTP server"); return false; } // 获取当前时间 struct tm timeinfo; time_t now = time(NULL); localtime_r(&now, &timeinfo); // 格式化日期和时间 char datetime_str[30]; strftime(datetime_str, sizeof(datetime_str), "%Y-%m-%d %H:%M:%S", &timeinfo); // 打印当前时间 ESP_LOGI("NTP", "Current time: %s", datetime_str); return true; } char FW_version[] = "Deskbooking(ESP32-C3)_SDK_v0.1_20250801"; void task_function(void *pvParameter) { uint8_t CPU_RunInfo[400]; while (1) { memset(CPU_RunInfo, 0, 400); vTaskGetRunTimeStats((char *)&CPU_RunInfo); printf("task_name run_cnt usage_rate \r\n"); printf("%s", CPU_RunInfo); printf("----------------------------------------------------\r\n"); vTaskDelay(500 / portTICK_PERIOD_MS); } } void print_wifi_and_bt_macAdress(){ uint8_t mac[6]; esp_wifi_get_mac(WIFI_IF_STA, mac); // 获取 STA 接口的 MAC 地址 ESP_LOGI("MAC", "Station MAC address: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); ESP_LOGI("app_main", "FW version: %s",FW_version); const uint8_t *bd_addr = esp_bt_dev_get_address(); // 打印蓝牙地址 char addr_str[18]; sprintf(addr_str, "%02x:%02x:%02x:%02x:%02x:%02x", bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); ESP_LOGI("app_main", "Bluetooth Address: %s", addr_str); } #define TAG "BLE_SCANNER" static bool ble_scanning = false; // 运行标志位 static esp_ble_scan_params_t ble_scan_params = { .scan_type = BLE_SCAN_TYPE_ACTIVE, .own_addr_type = BLE_ADDR_TYPE_PUBLIC, .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, .scan_interval = 0x50, .scan_window = 0x30, .scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE }; ble_random_device_t g_random_dev = {0}; /* 供 REST 接口读取 */ const ble_random_device_t *gap_get_random_device(void) { return &g_random_dev; } static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { switch (event) { case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: if (ble_scanning) { esp_ble_gap_start_scanning(2); // 2 秒 } break; case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: if (param->scan_start_cmpl.status == ESP_BT_STATUS_SUCCESS) { ESP_LOGI(TAG, "Scan started"); ble_scanning = true; } else { ESP_LOGE(TAG, "Scan start failed"); ble_scanning = false; } break; case ESP_GAP_BLE_SCAN_RESULT_EVT: { if (param->scan_rst.search_evt != ESP_GAP_SEARCH_INQ_RES_EVT) break; /* 打印设备信息 */ ESP_LOGI(TAG, "Device found: " ESP_BD_ADDR_STR, ESP_BD_ADDR_HEX(param->scan_rst.bda)); uint8_t *adv_name = NULL; uint8_t adv_name_len = 0; adv_name = esp_ble_resolve_adv_data_by_type( param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); if (adv_name) { ESP_LOGI(TAG, " Name: %.*s", adv_name_len, adv_name); } else { ESP_LOGI(TAG, " Name: <unknown>"); } ESP_LOGI(TAG, " RSSI: %d", param->scan_rst.rssi); /* 25% 概率随机保存到全局变量 */ if ((esp_random() & 0x3) == 0) { memcpy(g_random_dev.bda, param->scan_rst.bda, 6); g_random_dev.rssi = param->scan_rst.rssi; if (adv_name && adv_name_len < sizeof(g_random_dev.name)) { memcpy(g_random_dev.name, adv_name, adv_name_len); g_random_dev.name[adv_name_len] = '\0'; } else { strcpy(g_random_dev.name, "<unknown>"); } } break; } case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: ESP_LOGI(TAG, "Scan stopped"); if (scan_task_handle) { xTaskNotifyGive(scan_task_handle); } ble_scanning = false; vTaskDelay(pdMS_TO_TICKS(500)); esp_blufi_adv_start(); break; default: break; } } int ble_scan = 0; void ble_scan_task(void *param) { scan_task_handle = xTaskGetCurrentTaskHandle(); /* 1. 注册回调(只需一次,也可放在初始化里) */ static bool once = false; if (!once) { esp_ble_gap_register_callback(gap_event_handler); ESP_LOGE(TAG, "ble_scanner_init!"); once = true; } /* 2. 开始扫描 */ esp_ble_gap_set_scan_params(&ble_scan_params); esp_ble_gap_start_scanning(2); // 扫 5 秒 /* 3. 等扫描结束事件 */ ulTaskNotifyTake(pdTRUE, portMAX_DELAY); /* 4. 任务结束,自动销毁 */ ESP_LOGI(TAG, "One-shot BLE scan task exit"); scan_task_handle = NULL; // 任务退出前清理句柄 vTaskDelete(NULL); }为什么我的代码在蓝牙扫描task结束后log不会打印scan stop

最新推荐

recommend-type

cloudhsm-jvm-1.4.51-sources.jar

cloudhsm-jvm-1.4.51-sources.jar
recommend-type

sparkling-water-doc_2.12-3.42.0.3-1-3.4.jar

sparkling-water-doc_2.12-3.42.0.3-1-3.4.jar
recommend-type

Node.js构建的运动咖啡馆RESTful API介绍

标题《sportscafeold:体育咖啡馆》指出了项目名称为“体育咖啡馆”,这个名字暗示了该项目可能是一个结合了运动和休闲主题的咖啡馆相关的网络服务平台。该项目运用了多种技术栈,核心的开发语言为JavaScript,这从标签中可以得到明确的信息。 从描述中可以提取以下知识点: 1. **Node.js**:体育咖啡馆项目使用了Node.js作为服务器端运行环境。Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它能够使得JavaScript应用于服务器端开发。Node.js的事件驱动、非阻塞I/O模型使其适合处理大量并发连接,这对于RESTFUL API的构建尤为重要。 2. **Express Framework**:项目中使用了Express框架来创建RESTFUL API。Express是基于Node.js平台,快速、灵活且极简的Web应用开发框架。它提供了构建Web和移动应用的强大功能,是目前最流行的Node.js Web应用框架之一。RESTFUL API是一组遵循REST原则的应用架构,其设计宗旨是让Web服务通过HTTP协议进行通信,并且可以使用各种语言和技术实现。 3. **Mongoose ORM**:这个项目利用了Mongoose作为操作MongoDB数据库的接口。Mongoose是一个对象文档映射器(ODM),它为Node.js提供了MongoDB数据库的驱动。通过Mongoose可以定义数据模型,进行数据库操作和查询,从而简化了对MongoDB数据库的操作。 4. **Passport.js**:项目中采用了Passport.js库来实现身份验证系统。Passport是一个灵活的Node.js身份验证中间件,它支持多种验证策略,例如用户名和密码、OAuth等。它提供了标准化的方法来为用户登录提供认证,是用户认证功能的常用解决方案。 5. **版权信息**:项目的版权声明表明了Sportscafe 2015是版权所有者,这表明项目或其相关内容最早发布于2015年或之前。这可能表明该API背后有商业实体的支持或授权使用。 从【压缩包子文件的文件名称列表】中我们可以了解到,该文件的版本控制仓库使用的是“master”分支。在Git版本控制系统中,“master”分支通常用于存放当前可部署的稳定版本代码。在“master”分支上进行的更改通常都是经过测试且准备发布到生产环境的。 综上所述,我们可以知道体育咖啡馆项目是一个利用现代JavaScript技术栈搭建的后端服务。它包含了处理HTTP请求的Express框架、连接MongoDB数据库的Mongoose库和实现用户身份验证的Passport.js中间件。该项目可用于构建提供体育信息、咖啡馆菜单信息、预约服务等的Web应用或API服务,这为体育咖啡馆的营销、用户体验和数据管理提供了可能。 考虑到文档资料的提及,该项目的安装和API文档应该包含在项目资料中,可能在项目的README文件或其他说明文档中。对于项目的使用者或者开发者而言,这部分文档非常重要,因为它们可以提供详细的信息和指导,帮助用户快速部署和使用该API。 总结来说,这是一套针对体育咖啡馆相关业务的后端解决方案,它使用了流行的开源技术栈,可以灵活地应用于体育咖啡馆的网络服务中,如信息发布、在线预约、会员管理等。
recommend-type

【LNR优化与用户体验】:一文看透互操作优化如何提升用户感知

# 摘要 LNR(邻区关系优化)是提升移动通信网络性能与用户体验的关键技术。本文系统阐述了LNR优化的基本概念、理论基础与技术实现路径,构建了包括信道质量评估、干扰建模及关键性能指标分析在内的数学模型,并探讨了参数配置、邻区管理及AI与大数据在LNR优化中的应用。通过量化用户感知指标,分析了LNR优化对视频流畅度、页面加载速度及切换性能的实际改善效果,并结合典型场景验证了其优化成效。本文进一步展望了LNR技术在5G及未来网络中的发展趋势与技术挑战。
recommend-type

Java1.8 的编程语言、使用场景、版本号、厂商、是否开源、发行日期、终止日期、可替代产品、推荐产品是什么

以下是关于 **Java 1.8** 的全面信息汇总,涵盖其编程语言特性、使用场景、版本号、厂商、是否开源、发行日期、终止支持日期、可替代产品和推荐产品。 --- ## ✅ Java 1.8 综合信息表 | 项目 | 内容 | |------|------| | **编程语言** | Java | | **版本号** | Java 1.8(也称为 Java 8) | | **厂商** | Oracle、Adoptium、Amazon(Corretto)、Azul(Zulu)、Red Hat、IBM 等 | | **是否开源** | ✅ 是(OpenJDK 1.8 是开源的,Oracle
recommend-type

Java开发的教区牧民支持系统介绍

根据给定文件信息,下面将详细阐述相关知识点: ### 标题知识点 #### catecumenus-java: 教区牧民支持系统 - **Java技术栈应用**:标题提到的“catecumenus-java”表明这是一个使用Java语言开发的系统。Java是目前最流行的编程语言之一,广泛应用于企业级应用、Web开发、移动应用等,尤其是在需要跨平台运行的应用中。Java被设计为具有尽可能少的实现依赖,所以它可以在多种处理器上运行。 - **教区牧民支持系统**:从标题来看,这个系统可能面向的是教会管理或教区管理,用来支持牧民(教会领导者或牧师)的日常管理工作。具体功能可能包括教友信息管理、教区活动安排、宗教教育资料库、财务管理、教堂资源调配等。 ### 描述知识点 #### 儿茶类 - **儿茶素(Catechin)**:描述中提到的“儿茶类”可能与“catecumenus”(新信徒、教徒)有关联,暗示这个系统可能与教会或宗教教育相关。儿茶素是一类天然的多酚类化合物,常见于茶、巧克力等植物中,具有抗氧化、抗炎等多种生物活性,但在系统标题中可能并无直接关联。 - **系统版本号**:“0.0.1”表示这是一个非常初期的版本,意味着该系统可能刚刚开始开发,功能尚不完善。 ### 标签知识点 #### Java - **Java语言特点**:标签中明确提到了“Java”,这暗示了整个系统都是用Java编程语言开发的。Java的特点包括面向对象、跨平台(即一次编写,到处运行)、安全性、多线程处理能力等。系统使用Java进行开发,可能看重了这些特点,尤其是在构建可扩展、稳定的后台服务。 - **Java应用领域**:Java广泛应用于企业级应用开发中,包括Web应用程序、大型系统后台、桌面应用以及移动应用(Android)。所以,此系统可能也会涉及这些技术层面。 ### 压缩包子文件的文件名称列表知识点 #### catecumenus-java-master - **Git项目结构**:文件名称中的“master”表明了这是Git版本控制系统中的一个主分支。在Git中,“master”分支通常被用作项目的主干,是默认的开发分支,所有开发工作都是基于此分支进行的。 - **项目目录结构**:在Git项目中,“catecumenus-java”文件夹应该包含了系统的源代码、资源文件、构建脚本、文档等。文件夹可能包含各种子文件夹和文件,比如src目录存放Java源代码,lib目录存放相关依赖库,以及可能的build.xml文件用于构建过程(如Ant或Maven构建脚本)。 ### 结合以上信息的知识点整合 综合以上信息,我们可以推断“catecumenus-java: 教区牧民支持系统”是一个使用Java语言开发的系统,可能正处于初级开发阶段。这个系统可能是为了支持教会内部管理,提供信息管理、资源调度等功能。其使用Java语言的目的可能是希望利用Java的多线程处理能力、跨平台特性和强大的企业级应用支持能力,以实现一个稳定和可扩展的系统。项目结构遵循了Git版本控制的规范,并且可能采用了模块化的开发方式,各个功能模块的代码和资源文件都有序地组织在不同的子文件夹内。 该系统可能采取敏捷开发模式,随着版本号的增加,系统功能将逐步完善和丰富。由于是面向教会的内部支持系统,对系统的用户界面友好性、安全性和数据保护可能会有较高的要求。此外,考虑到宗教性质的敏感性,系统的开发和使用可能还需要遵守特定的隐私和法律法规。
recommend-type

LNR切换成功率提升秘籍:参数配置到网络策略的全面指南

# 摘要 LNR(LTE to NR)切换技术是5G网络部署中的关键环节,直接影
recommend-type

How to install watt toolkit in linux ?

安装 Watt Toolkit(原名 Steam++)在 Linux 系统上通常可以通过编译源码或者使用预编译的二进制文件来完成。Watt Toolkit 是一个开源工具,主要用于加速 Steam 平台的下载速度,支持跨平台运行,因此在 Linux 上也能够很好地工作。 ### 安装步骤 #### 方法一:使用预编译的二进制文件 1. 访问 [Watt Toolkit 的 GitHub 仓库](https://github.com/BeyondDimension/SteamTools) 并下载适用于 Linux 的最新版本。 2. 解压下载的压缩包。 3. 给予可执行权限: ```
recommend-type

PHP实现用户墙上帖子与评论的分享功能

根据给定文件信息,我们可以推导出与“userwallposts”相关的知识点。这里涉及的关键概念包括用户墙面墙(User Wall)、帖子(Posts)和评论(Comments),以及它们在编程语言PHP中的实现方式。用户墙是一种允许用户发布信息,并让他们的朋友或跟随者查看并参与讨论的功能,常见于社交网站。 ### 用户墙概念 用户墙类似于现实生活中的一面墙,用户可以在上面贴上“帖子”来分享自己的想法、照片、视频等信息。其他用户可以在这些帖子下面进行“评论”,类似于在墙上留言。这种互动方式构建了一个社区式的交流环境,增加了用户之间的互动性和参与感。 ### 用户墙的实现 在PHP中实现用户墙功能需要处理前端用户界面和后端服务器逻辑。前端负责展示用户墙、帖子和评论的界面,而后端则负责存储、检索和管理这些数据。 1. **前端实现**:前端可以使用HTML、CSS和JavaScript来构建用户墙的界面。使用AJAX技术可以让用户无需刷新页面即可提交和获取新的帖子和评论。此外,可能还会用到模板引擎(如Twig或Smarty)来动态生成页面内容。 2. **后端实现**:后端PHP代码将负责处理前端发送的请求,如帖子和评论的添加、删除和检索。数据库(如MySQL)将用于存储用户信息、帖子内容、评论以及它们之间的关联关系。 3. **数据库设计**: - 用户表(users):存储用户信息,例如用户名、密码(加密存储)、用户状态等。 - 帖子表(posts):存储帖子信息,例如帖子ID、帖子内容、发帖时间、所属用户ID等。 - 评论表(comments):存储评论信息,包括评论ID、评论内容、评论时间、所属帖子ID和用户ID等。 4. **PHP与数据库交互**:使用PDO(PHP Data Objects)或mysqli扩展来执行SQL语句与数据库进行交互。PDO提供了数据库访问的抽象层,可以连接多种数据库系统,而mysqli则针对MySQL进行了优化。 5. **安全性**: - 输入验证:为了防止SQL注入等安全问题,需要对用户输入进行验证和清理。 - 输出编码:在将数据输出到浏览器之前,应将特殊字符转换为HTML实体。 - 用户认证:用户登录系统时,应采取安全措施如使用会话管理(session management)和防止跨站请求伪造(CSRF)。 6. **功能实现细节**: - 发布帖子:用户输入帖子内容并提交,后端接收并存储到帖子表中。 - 显示帖子:从帖子表中检索所有帖子并展示在用户墙上,包括帖子标题、内容、发布时间和发帖人等信息。 - 发布评论:用户对特定帖子发表评论,后端接收评论信息并将其存储到评论表中。 - 显示评论:为每个帖子显示其下的所有评论,包括评论内容、时间、评论者等。 ### 开源项目实践 “userwallposts-master”暗示了可能存在一个与用户墙帖子和评论相关的开源项目或代码库。这个项目可能包含预设的代码和文件结构,允许开发者下载、安装和配置来创建他们自己的用户墙功能。开发人员可以使用这个项目作为起点,根据自己的需求进一步定制和扩展功能。 在实际开发过程中,还需要考虑系统的可扩展性和维护性。例如,可以设计RESTful API让前端和后端分离,或者使用现代的PHP框架(如Laravel、Symfony等)来简化开发流程和提高代码的组织性。 在总结上述内容后,我们可以了解到用户墙是社交平台中常见的一种功能,其核心功能包括发布帖子和评论。在PHP环境下实现这样的功能需要对前端界面和后端逻辑有深入的理解,以及对数据库设计和交互的安全性有一定的认识。开源项目如“userwallposts-master”可能提供了一个基础框架,帮助开发者快速构建和部署一个用户墙系统。
recommend-type

【LNR信令深度解析】:MR-DC双连接建立全过程技术揭秘

# 摘要 本文系统探讨了LNR信令与MR-DC双连接技术的基本原理、架构组成及其关键信令流程。深入分析了MR-DC的网络架构分类、核心网元功能、无线承载管理机制以及双连接建立过程中的关键信令交互路径。同时,文章解析了LNR信令消息的结构特征与关键字段,探讨了MR-DC场景下的性能评估指标与优化策略,包括信令压缩、负载均衡及节能调度机制。最后,文章展望了MR-DC技术在5G