691 lines
25 KiB
ReStructuredText
Raw Permalink Normal View History

2025-10-10 16:07:00 +08:00
中控(Central)
======================================
:link_to_translation:`en:[English]`
1 功能概述
-------------------------------------
本工程用于手机、拨号盘等主设备场景,主要功能有
| 1.作为a2dp source向对端音响传输音乐数据
| 2.接受对端的控制(播放暂停)
| 3.ble gatt server/gatt client
1.1 软件规格
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
* a2dp
* avdtp source
* avrcp
* tg
* ct
* ble:
* gap
* gatt server
* gatt client
* smp legacy pair/secure connection pair
1.2 代码路径及编译命令
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Demo路径`./projects/bluetooth/central <https://gitlab.bekencorp.com/wifi/armino/-/tree/main/projects/bluetooth/central>`_
编译命令:``make bk7258 PROJECT=bluetooth/central``
2 cmd命令简介
-------------------------------------
2.1 a2dp source
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+--------------------------------------------------+---------------------------+
| a2dp_player connect <xx:xx:xx:xx:xx:xx> | 连接音响 |
+--------------------------------------------------+---------------------------+
| a2dp_player disconnect <xx:xx:xx:xx:xx:xx> | 断开连接 |
+--------------------------------------------------+---------------------------+
| a2dp_player play <xxx.mp3> | 播放mp3 |
+--------------------------------------------------+---------------------------+
| a2dp_player stop | 停止播放 |
+--------------------------------------------------+---------------------------+
| a2dp_player pause | 暂停 |
+--------------------------------------------------+---------------------------+
| a2dp_player resume | 恢复 |
+--------------------------------------------------+---------------------------+
| a2dp_player abs_vol <xxx> | 设置音响绝对音量 0 ~ 127 |
| | (是否有效视对端而定) |
+--------------------------------------------------+---------------------------+
2.2 ble gatt
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+-------------------------------------------------------------+--------------------------------------+
| ble_gatt_demo -h | 显示详细命令 |
+-------------------------------------------------------------+--------------------------------------+
| ble_gatt_demo <gatts|gattc> init | gatts/gattc初始化 |
+-------------------------------------------------------------+--------------------------------------+
| ble_gatt_demo gatts disconnect <xx:xx:xx:xx:xx:xx> | gatts断开连接 |
+-------------------------------------------------------------+--------------------------------------+
| ble_gatt_demo gattc connect <xx:xx:xx:xx:xx:xx> <0|1> | 连接gatts0为public1为random |
+-------------------------------------------------------------+--------------------------------------+
| ble_gatt_demo gattc disconnect <xx:xx:xx:xx:xx:xx> | gattc断开连接 |
+-------------------------------------------------------------+--------------------------------------+
| ble_gatt_demo gattc connect_cancel | 取消连接 |
+-------------------------------------------------------------+--------------------------------------+
| ble_gatt_demo update_param <xx:xx:xx:xx:xx:xx> | 更新连接参数 |
| <interval> <timeout> | |
+-------------------------------------------------------------+--------------------------------------+
3 a2dp source 测试
-------------------------------------
3.1 测试过程
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.准备一张sd卡格式化成exfat将project/bluetooth/central/1_qcs.mp3放入根目录。(必须是16bits的mp3)
| 2.插入sd卡开机。
| 3.令音响进入配对模式
| 4.输入 ``a2dp_player connect xx:xx:xx:xx:xx:xx``其中xx为音响地址。等待连接成功
| 5.如果连接成功,会提示"a2dp connect complete",如果连接失败,会提示"Unsuccessful Connection Complete"之类的log。
| 6.输入 ``a2dp_player play xxx.mp3``
| 7.如果sd卡正常会提示"f_mount OK",如果音乐文件存在,会提示"mp3 file open successfully"
| 8.此时可听到播出声音
| 9.正在播放的情况下可以stop pause停止播放的情况下可以play。(尽量连接后立刻play不要stop参见本章节兼容性说明)
| 10.如果音响支持avrcp可以通过音响控制播放暂停。(存在兼容性问题,参见本章节兼容性说明)
3.2 兼容性说明
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.仅播放歌曲场景某些音响如果长时间处于stop(本地a2dp_player stop 或对端avdtp suspend)状态会主动断开连接。log会提示bt_api_event_cb:Disconnected from xx:xx:xx:xx:xx:xx
| 2.某些音响不会向本地注册avrcp playback notify会导致两端操作播放暂停时状态不一致的现象。
| 3.某些音响不会向本地报告avrcp volume change此时音响调节音量central无法得知。
| 4.某些音响不支持设置绝对音量。
3.3 其他注意事项
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.如果sdcard有问题会出现 f_mount failed 或 read data crc error 的提示
4 ble gatt 测试
-------------------------------------
4.1 单板作为client与手机连接测试
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.手机使用nrf connect开启广播
| 2.开发板a输入 ``ble_gatt_demo gattc init``
| 3.开发板a输入 ``ble_gatt_demo gattc connect <手机adv地址> 1``
| 3.连接成功会有log打印 ``BK_BLE_GAP_CONNECT_COMPLETE_EVT``
| 4.discover完成会有打印 ``BK_GATTC_DIS_SRVC_CMPL_EVT``
4.2 双板对测
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.开发板a输入 ``ble_gatt_demo gatts init``
| 2.开发板b输入 ``ble_gatt_demo gattc init``
| 3.开发板b输入 ``ble_gatt_demo gattc connect <a板地址> 1``
| 4.连接成功会有log打印 ``BK_BLE_GAP_CONNECT_COMPLETE_EVT``
| 5.b板discover完成会有打印 ``BK_GATTC_DIS_SRVC_CMPL_EVT``
| 6.后续a板会定时给b板notify
5 结构图
-------------------------------------
5.1 运行时
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
.. figure:: ../../../../_static/bluetooth_central_runtime_arch.png
:align: center
:alt: module architecture Overview
:figclass: align-center
Figure 1. software module architecture
5.2 流程图
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
.. figure:: ../../../../_static/bluetooth_central_flow_chart.png
:align: center
:alt: module architecture Overview
:figclass: align-center
Figure 2. flow chart
6 重要流程说明
-------------------------------------
6.1 连接音响
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
int bt_a2dp_source_demo_connect(uint8_t *addr)
{
...
//连接对端
err = bk_bt_a2dp_source_connect(a2dp_env.peer_addr.addr);
if (err)
{
a2dp_loge("connect a2dp err %d", err);
goto error;
}
a2dp_logi("start wait a2dp connect cb");
//等待连接成功
err = rtos_get_semaphore(&s_bt_api_event_cb_sema, 12 * 1000);
if (err)
{
a2dp_loge("get sem for connect err");
goto error;
}
a2dp_logi("start wait a2dp cap report cb");
//等待获取a2dp cap
err = rtos_get_semaphore(&s_bt_api_event_cb_sema, 6 * 1000);
if (err)
{
a2dp_loge("get sem for cap select err");
goto error;
}
a2dp_logi("a2dp connect complete");
...
}
6.2 mp3解码
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
static void bt_a2dp_source_decode_task(void *arg)
{
...
while (*task_ctrl)
{
...
if (0 != mp3_read_end_ptr - current_mp3_read_ptr - bytesleft)
{
//读取文件
fr = f_read(&mp3file, current_mp3_read_ptr + bytesleft, mp3_read_end_ptr - current_mp3_read_ptr - bytesleft, &num_rd);
if (fr != FR_OK)
{
a2dp_loge("read %d %s failed!", num_rd, full_path);
goto error;
}
if (!num_rd)
{
//回到文件头
a2dp_logi("file end, return to begin");
os_memmove(mp3_read_start_ptr, current_mp3_read_ptr, bytesleft);
current_mp3_read_ptr = mp3_read_start_ptr;
f_lseek(&mp3file, frame_start_offset);
continue;
}
...
}
a2dp_logv("bytesleft %d %p", bytesleft, current_mp3_read_ptr);
do
{
...
//判断ring buffer是否满
while (ring_buffer_particle_len(&s_rb_ctx) > s_decode_trigger_size)
{
if (!*task_ctrl)
{
goto error;
}
a2dp_logd("ring buffer not read too much, wait %d", ring_buffer_particle_len(&s_rb_ctx));
rtos_get_semaphore(&s_source_need_decode_sema, BEKEN_WAIT_FOREVER);
}
//解码
ret = MP3Decode(s_mp3_decoder, &current_mp3_read_ptr, &bytesleft, (int16_t *)pcm_write_ptr, 0);
//异常处理
if (ret != ERR_MP3_NONE)
{
if (ERR_MP3_INDATA_UNDERFLOW == ret)
{
bytesleft = last_success_bytesleft;
current_mp3_read_ptr = last_success_read_ptr;
break;
}
goto error;
}
//写ring buffer
if (ring_buffer_particle_write(&s_rb_ctx, pcm_write_ptr, tmp_mp3_frame_info.outputSamps * tmp_mp3_frame_info.bitsPerSample / 8))
{
a2dp_logd("ring_buffer full %d", ring_buffer_particle_len(&s_rb_ctx));
...
continue;
}
else
{
a2dp_logv("write %d, %d", tmp_mp3_frame_info.outputSamps * tmp_mp3_frame_info.bitsPerSample / 8, ring_buffer_particle_len(&s_rb_ctx));
}
pcm_decode_size += tmp_mp3_frame_info.outputSamps * tmp_mp3_frame_info.bitsPerSample / 8;
}
while (tmp_mp3_frame_info.outputSamps && *task_ctrl);
}
...
}
6.3 host a2dp 取数回调(pcm)
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
static int32_t a2dp_source_data_cb(uint8_t *buf, int32_t len)
{
uint32_t read_len = 0;
...
//从ring buffer读取
if (ring_buffer_particle_len(&s_rb_ctx) < len)
{
a2dp_loge("ring buffer not enough data %d < %d ", ring_buffer_particle_len(&s_rb_ctx), len);
}
else
{
ring_buffer_particle_read(&s_rb_ctx, buf, len, &read_len);
}
//通知mp3继续解码
if (s_source_need_decode_sema)
{
rtos_set_semaphore(&s_source_need_decode_sema);
}
return read_len;
}
6.3 host a2dp 重采样回调
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
static int32_t a2dp_source_pcm_resample_cb(uint8_t *in_addr, uint32_t *in_len, uint8_t *out_addr, uint32_t *out_len)
{
...
bt_audio_resample_req_t rsp_req;
os_memset(&rsp_req, 0, sizeof(rsp_req));
input_len = *in_len;
output_len = *out_len;
rsp_req.in_addr = in_addr;
rsp_req.out_addr = out_addr;
rsp_req.in_bytes_ptr = &input_len;
rsp_req.out_bytes_ptr = &output_len;
//发送给cpu1重采样
ret = media_send_msg_sync(EVENT_BT_PCM_RESAMPLE_REQ, (uint32_t)&rsp_req);
if (ret)
{
a2dp_loge("EVENT_BT_PCM_RESAMPLE_REQ err %d !!", ret);
ret = -1;
}
...
return ret;
}
6.4 host a2dp sbc编码回调
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
static int32_t a2dp_source_pcm_encode_cb(uint8_t type, uint8_t *in_addr, uint32_t *in_len, uint8_t *out_addr, uint32_t *out_len)
{
...
bt_audio_encode_req_t rsp_req;
int ret = 0;
os_memset(&rsp_req, 0, sizeof(rsp_req));
rsp_req.handle = &s_sbc_software_encoder_ctx;
rsp_req.in_addr = in_addr;
rsp_req.type = type;
rsp_req.out_len_ptr = (typeof(rsp_req.out_len_ptr))&encode_len;
//发送给cpu1编码
ret = media_send_msg_sync(EVENT_BT_PCM_ENCODE_REQ, (uint32_t)&rsp_req);
if (ret)
{
a2dp_loge("EVENT_BT_PCM_ENCODE_REQ err %d !!", ret);
return -1;
}
...
return 0;
}
6.5 ble gap初始化
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
int dm_gatt_main(cli_gatt_param_t *param)
{
...
//注册gap回调
bk_ble_gap_register_callback(dm_ble_gap_private_cb);
dm_gatt_add_gap_callback(dm_ble_gap_common_cb);
//读取本地ir/er
bluetooth_storage_read_local_key(&s_dm_gap_local_key);
//向host设置ir/er
ret = bk_ble_gap_set_security_param(BK_BLE_SM_SET_ER, (void *)s_dm_gap_local_key.er, sizeof(s_dm_gap_local_key.er));
...
ret = bk_ble_gap_set_security_param(BK_BLE_SM_SET_IR, (void *)s_dm_gap_local_key.ir, sizeof(s_dm_gap_local_key.ir));
//生成rpa地址
...
ret = bk_ble_gap_generate_rpa(NULL);
...
//设置privacy
ret = bk_ble_gap_config_local_privacy(s_dm_gatt_privacy_enable);
//循环添加已配对设备
for()
{
ret = bk_ble_gap_bond_dev_list_operation(BK_GAP_BOND_DEV_LIST_OPERATION_ADD, &bond_dev);
}
//设置iocap
ret = bk_ble_gap_set_security_param(BK_BLE_SM_IOCAP_MODE, (void *)&s_dm_gatt_iocap, sizeof(s_dm_gatt_iocap));
//设置配对请求auth参数
ret = bk_ble_gap_set_security_param(BK_BLE_SM_AUTHEN_REQ_MODE, (void *)&s_dm_gatt_auth_req, sizeof(s_dm_gatt_auth_req));
//设置密钥分发种类
ret = bk_ble_gap_set_security_param(BK_BLE_SM_SET_INIT_KEY, (void *)&s_dm_gatt_init_key_distr, sizeof(s_dm_gatt_init_key_distr));
ret = bk_ble_gap_set_security_param(BK_BLE_SM_SET_RSP_KEY, (void *)&s_dm_gatt_rsp_key_distr, sizeof(s_dm_gatt_rsp_key_distr));
//设置gatt mtu
bk_ble_gatt_set_local_mtu(517);
}
6.6 ble gatts初始化
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
int dm_gatts_main(cli_gatt_param_t *param)
{
//初始化gap
dm_gatt_main(NULL);
//注册gatts回调注册gatts app
bk_ble_gatts_register_callback(bk_gatts_cb);
ret = bk_ble_gatts_app_register(0);
//设置service
ret = bk_ble_gatts_create_attr_tab(s_gatts_attr_db_service_1, s_gatts_if, sizeof(s_gatts_attr_db_service_1) / sizeof(s_gatts_attr_db_service_1[0]), 30);
ret = bk_ble_gatts_create_attr_tab(s_gatts_attr_db_service_2, s_gatts_if, sizeof(s_gatts_attr_db_service_2) / sizeof(s_gatts_attr_db_service_2[0]), 30);
//开启service
bk_ble_gatts_start_service(s_service_attr_handle);
//注册gap回调(仅gatts关心)
dm_gatt_add_gap_callback(dm_ble_gap_cb);
//设置adv参数
ret = dm_gatts_set_adv_param(s_dm_gatts_local_addr_is_public);
//设置adv random addr(仅rpa开启或自定义addr)
if (need_set_random_addr)
{
ret = bk_ble_gap_set_adv_rand_addr(ADV_HANDLE, current_addr);
if (ret)
{
gatt_loge("bk_ble_gap_set_adv_rand_addr err %d", ret);
goto error;
}
ret = rtos_get_semaphore(&s_ble_sema, SYNC_CMD_TIMEOUT_MS);
if (ret != kNoErr)
{
gatt_loge("wait set adv rand addr err %d", ret);
goto error;
}
}
//设置adv data
ret = bk_ble_gap_set_adv_data((bk_ble_adv_data_t *)&adv_data);
//开启adv
ret = bk_ble_gap_adv_start(1, &ext_adv);
...
}
6.7 ble gattc初始化
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
int dm_gattc_main(cli_gatt_param_t *param)
{
...
//注册gap回调(仅gattc关心)
dm_gatt_add_gap_callback(dm_ble_gap_cb);
...
//注册gattc回调
bk_ble_gattc_register_callback(bk_gattc_cb);
...
//注册gattc app
ret = bk_ble_gattc_app_register(0);
...
//设置connect/scan rand addr(仅rpa开启或自定义addr)
if (need_set_random_addr)
{
ret = bk_ble_gap_set_rand_addr(current_addr);
if (ret)
{
gatt_loge("bk_ble_gap_set_rand_addr err %d", ret);
goto error;
}
ret = rtos_get_semaphore(&s_ble_sema, SYNC_CMD_TIMEOUT_MS);
if (ret != kNoErr)
{
gatt_loge("wait set rand addr err %d", ret);
goto error;
}
}
...
}
6.8 ble gattc 连接
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::
int32_t dm_gattc_connect(uint8_t *addr, uint32_t addr_type)
{
...
//设置连接参数
bk_gap_create_conn_params_t param = {0};
bk_bd_addr_t peer_id_addr = {0};
bk_ble_addr_type_t peer_id_addr_type = BLE_ADDR_TYPE_PUBLIC;
param.scan_interval = 800;
param.scan_window = param.scan_interval / 2;
param.initiator_filter_policy = 0;
//决定是否用rpa连接
if (g_dm_gap_use_rpa && 0 == dm_gatt_find_id_info_by_nominal_info(addr, addr_type, peer_id_addr, &peer_id_addr_type))
{
gatt_logi("local use rpa");
param.local_addr_type = (s_dm_gattc_local_addr_is_public ? BLE_ADDR_TYPE_RPA_PUBLIC : BLE_ADDR_TYPE_RPA_RANDOM);
os_memcpy(param.peer_addr, addr, sizeof(param.peer_addr));
param.peer_addr_type = addr_type;
}
else
{
param.local_addr_type = (s_dm_gattc_local_addr_is_public ? BLE_ADDR_TYPE_PUBLIC : BLE_ADDR_TYPE_RANDOM);
os_memcpy(param.peer_addr, addr, sizeof(param.peer_addr));
param.peer_addr_type = addr_type;
}
//设置连接参数
param.conn_interval_min = 16;
param.conn_interval_max = 16;
param.conn_latency = 0;
param.supervision_timeout = 500;
param.min_ce = 0;
param.max_ce = 0;
err = bk_ble_gap_connect(&param);
...
return err;
}
7 常见问题FAQ
-------------------------------------
7.1 ble连接、断连evt是怎样的顺序
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1. BK_BLE_GAP_CONNECT_COMPLETE_EVT -> dm_gatts.c dm_gattc.c BK_GATTS_CONNECT_EVT|BK_GATTC_CONNECT_EVT -> 各个上层profile的 BK_GATTS_CONNECT_EVT|BK_GATTC_CONNECT_EVT
| 2. 各个上层profile的 BK_GATTS_DISCONNECT_EVT|BK_GATTC_DISCONNECT_EVT -> dm_gatts.c dm_gattc.c BK_GATTS_DISCONNECT_EVT|BK_GATTC_DISCONNECT_EVT -> BK_BLE_GAP_CONNECT_COMPLETE_EVT
7.2 蓝牙多模(bt/ble)链接的有哪些库?
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| libbluetooth_host_dm_dual.a 和 libbluetooth_controller_dual.a
7.3 对于一个已存在的ble链路有没有handle之类的以便于控制
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| BK_GATTS_CONNECT_EVT和 BK_GATTC_CONNECT_EVT中有conn_id所有gatts/gattc接口都以此作为handle。这些evt也包含对端addr可供上层作映射关系。
| BK_BLE_GAP_CONNECT_COMPLETE_EVT也有hci_handle但不能在gatt直接使用需要通过转换接口。
7.4 如何创建gatts db如何将其和attribute handle对应起来
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.请参考dm_gatts.c的表结构。
| 2.表reg成功后会上报BK_GATTS_CREAT_ATTR_TAB_EVThandles对应表每一行的attribute handle(其中char decl/char value只有后者有效)
7.5 bk_ble_gap_register_callback能不能复用比如多个profile都想收到evt
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 不能但在dm_gatt.c里有个dm_gatt_add_gap_callback通过bk_ble_gap_register_callback封装了这个功能更多细节请参考dm_gatts.c dm_gattc.c及现有profile的实现
7.6 attribute handle的evt能不能分别给到各个profile
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 请参考dm_gatts_reg_db的实现
7.7 各个profile能否收到gatts的evt
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 请参考dm_gatts_reg_db的实现目前已添加了几个evt可以根据需要修改
7.8 配对相关的evt有哪些流程
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| BK_BLE_GAP_SEC_REQ_EVT 配对请求
| BK_BLE_GAP_AUTH_CMPL_EVT 配对结果
| BK_BLE_GAP_BOND_KEY_GENERATE_EVT key生成
| BK_BLE_GAP_PASSKEY_NOTIF_EVT passkey生成通知
| BK_BLE_GAP_PASSKEY_REQ_EVT 本地输入passkey req evt
| BK_BLE_GAP_NC_REQ_EVT 本地number compare请求
| 大致流程是BK_BLE_GAP_SEC_REQ_EVT -> passkey、number compare(如果有) -> BK_BLE_GAP_BOND_KEY_GENERATE_EVT -> BK_BLE_GAP_AUTH_CMPL_EVT
7.9 app应该存储key吗
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 需要BK_BLE_GAP_BOND_KEY_GENERATE_EVT需要存入flash
7.10 绑定(bond)和解绑流程?
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.绑定BK_BLE_GAP_BOND_KEY_GENERATE_EVT后需要存入flash
| 2.解绑通过bk_ble_gap_bond_dev_list_operation 删除(有限制)
7.11 绑定相关还有哪些注意事项?
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.绑定涉及到的存储分app部分和sdk部分
| 2.配对成功后sdk上报BK_BLE_GAP_BOND_KEY_GENERATE_EVTapp需要将key存入flash中以备下次开机使用。sdk也会存储这部分key但只是在ram里。
| 3.配对成功后如果断连并第二次连接如果对端请求加密、鉴权结果也会在BK_BLE_GAP_AUTH_CMPL_EVT体现
| 4.配对失败(或者加密、鉴权失败)auth_cmpl.success为0则app需要将对应key从flash删除
| 5.一旦app决定要删除key则同时还需要调用bk_ble_gap_bond_dev_list_operation删除sdk存储的key
| 6.使用bk_ble_gap_bond_dev_list_operation时要保证当前ble不在广播、扫描状态。
| 7.使用bk_ble_gap_bond_dev_list_operation删除或清空key时sdk不会断开涉及的链路
| 8.开机蓝牙初始化后开广播、扫描前需要用bk_ble_gap_bond_dev_list_operation将先前BK_BLE_GAP_BOND_KEY_GENERATE_EVT的key添加给sdk
7.12 如何修改ble地址
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 1.如果是public则通过bk_get_mac获取可以通过bk_set_base_mac设置(具体请参考对应文档)。bk_ble_gap_ext_adv_params_t.own_addr_type = BLE_ADDR_TYPE_PUBLIC; bk_gap_create_conn_params_t.local_addr_type = BLE_ADDR_TYPE_PUBLIC
| 2.如果是random对于发advbk_ble_gap_set_adv_rand_addr设置地址且bk_ble_gap_ext_adv_params_t.own_addr_type = BLE_ADDR_TYPE_RANDOM; 对于master或扫描bk_ble_gap_set_rand_addr设置地址且bk_gap_create_conn_params_t.local_addr_type = BLE_ADDR_TYPE_RANDOM
7.13 bt、ble public addr能否不一样
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 目前只能一样
7.14 rpa是什么意思
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| RPA(resolvable private address): ble一种防止跟踪的随机地址生成、使用机制基于random addr开启后adv、scan、connect的local addr由特殊算法生成在空口上看是随机的。
7.15 ble如何使用rpa
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| dm_gatt.c dm_gatts.c dm_gattc.c里g_dm_gap_use_rpa = 1; s_dm_gattc_local_addr_is_public = 0; s_dm_gatts_local_addr_is_public = 0;
7.16 ble如果配对使用推荐用哪种地址
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
| 只推荐public或rpa单纯random addr会在与手机交互的场景里出现兼容性问题。