BT
前言
bt主要是控制命令下发和事件上报,其所有控制命令和事件都在“bt_device.h”文件中枚举出来了,其中事件的上报都在“bt_service.c”文件的“app_bt_notify”函数中根据类型调用相应的函数进行处理。
控制可以有两种方式调用:
调用“void send_bt_control_msg_to_app_thread(bt_control_cmd_t cmd, uint8_t *data, uint16_t data_len)”函数发送到BT线程异步调用。
直接调用“bt_comm.c"文件中的对应函数。
注:
其中“bt_comm.c"文件中是函数是我们封装出来的,有的命令可能没有对应的函数,而方法1都是支持的。
如使用方法1时其返回值在“BT_EVENT_CONTROL_RET”事件中。
"bt_service.c"文件的"app_bt_notify"函数中的事件处函数请不要做修改,以防止在后继升级过程中不好合代码。如想按自己的逻辑处理BT事件,请参见“BT事件自定义处理”。
一键连接
双模蓝牙因为同时支持BT和BLE,需要分别建立BT和BLE的连接以及可能的配对,在更早之前的蓝牙连接中,通常BT和BLE会使用不同地址,这样终端用户会感知到建立两个连接的过程,甚至对于IOS,因为手机APK不能操作BT连接接口,终端用户必须亲自手动建立BT连接。而一键连接就是为了改善用户体验,使得终端用户只需要操作一次即可连接BT和BLE。
蓝牙协议有个Cross-Transport Key Derivation(CTKD)的功能,可以让BT/BLE根据BLE/BT配对生成的Key直接生成自己的Key,使得BT和BLE本来需要的两次配对变成一次。当然连接依旧是独立的两个连接。
这个在IOS和安卓/鸿蒙操作系统上又有不同,IOS系统是在IOS13以后全平台支持该功能,只是需要在APK创建BLE连接时候有特殊调用,这个在后续章节说明;而安卓/鸿蒙系统,部分支持部分不支持,加上安卓开发时BLE不配对场景居多,所以安卓/鸿蒙系统的一键连接是依靠手机APK主动创建BLE和BT来实现。
IOS系统
IOS系统只要IOS13以上,都支持CTKD,要完成一键连接,需要以下流程:
通过手机APK连接设备BLE,连接前需要设置connectOption:CBConnectPeripheralOptionEnableTransportBridgingKey,下图是设置示例
触发BLE配对,从手机端或设备端均可,此时手机会弹出配对框,点击确认配对。
在BLE配对完成后,只要设备端正常处于被连接状态,手机会自动发起BT的连接。
需要注意,手机发起BT连接之前,需要一直在APK界面等待,如果设置CTKD的APK在触发BLE配对后被放到后台,IOS不会发起BT连接
IOS会自动完成HFP、A2DP、AVRCP及HID的连接。
安卓/鸿蒙系统
和IOS系统不同,安卓/鸿蒙系统的BT/BLE连接都需要手机APK主动发起,但做法上分成以下两种:
BLE和BT使用相同地址。在BLE连接上以后,再调用安卓/鸿蒙CreateBond接口创建BT连接。
这种方式需要注意以下几点点:部分手机系统在处理BLE/BT相同地址的场景,在配对BT的时候必须要求BLE属性是双模设备才会发起,否则不会发起连接。要让手机认为设备为双模只有以下两种方式,APK需要满足其中至少一种:
通过BLE扫描到设备的广播包且广播包的flag没有not support edr的bit,flag默认SDK已经设置好。因此APK只需要保证无论是通过扫描发起连接设备还是扫二维码发起连接设备,都需要做BLE的扫描,扫描到以后再发起连接。
发起BT配对前,先做BT的扫描,扫描到BT设备再发起配对
建议使用方法a,因为BLE扫描速度通常是比BT扫描要快很多。
部分手机虽然APK没有发起BLE的配对,但只要发起了BT配对,手机会先配对BLE,才会配对BT。这个行为不会多弹一个确认框,但有些手机在处理配对后BT/BLE地址有问题,当手机开关蓝牙后,BT或BLE的LinkKey会丢失,对应连接在回连时候会重新配对,这个时候有可能弹框有可能不弹框。
BLE和BT使用不同地址,Solution SDK提供了接口“bt_err_t app_bt_cfg_change_bt_addr(bt_change_bd_addr_method_t type, uint8_t *addr)”可以改变BT的地址,这样可以避免做法1里面遇到的限制a/b。但这种方法也有需要注意的地方:
因为IOS的CTKD必须要地址相同,所以要确保连接IOS的时候把地址切回和BLE相同,和安卓连接的时候再切换为不同地址。Solution SDK已经提供完整方案,可以直接使用或者参考(“BT_USING_CUSTOMIZE_MAC”宏控制,ble连接成功后APP同步手机类型到手表端,是安卓时函数参数为(BT_CH_BD_METHOD_PRESERVE, NULL),是IOS时函数参数为(BT_CH_BD_METHOD_ORIGIN, NULL)。这样手机时安卓时BT的地址就是ble的MAC地址最后一位异或上0x55。
解除配对
终端用户可以在手机端解除配对,也可以在设备端恢复出厂设置或调用解除配对函数。
如果是手机端解除配对,分为解除配对时BT/BLE已经连接和没有连接:
如果BT/BLE已经连接,需要发命令通知设备端删除相关信息。如果是IOS设备,需要提醒用户在手机设置里面删除配对信息,否则会出现IOS的BLE回连中第ii点提到的不停被回连。
如果BT/BLE没有连接,手机APK要确保不再回连BLE并删除手机的BT配对信息,这样设备端在BT回连时才能收到LinkKey Missing的错误停止回连并删除相关信息。
如果是设备端恢复出厂设置,只要删除相关信息就好。
调用解除配对函数:
void app_bt_delete_appoint_peer_addr(bt_mac_t *mac);
配对弹窗
要开启设备端BT配对弹窗,需要打开配置“BT_USING_PAIRING_CONFIRMATION”,当打开此配置后BT配对时有对应的事件上报
case BT_EVENT_IO_CAPABILITY_IND:
{
bt_io_capability_rsp_t res;
res.io_capability = CAPABILITY_DISPLAY_YES_NO; //In factory mode, the value is CAPABILITY_NO_INPUT_NO_OUTPUT
rt_memcpy(res.mac.addr, args->args, sizeof(res.mac.addr));
res.mitm = false;
res.bonding = true;
send_bt_control_msg_to_app_thread(BT_CONTROL_IO_CAPABILITY_RES, (uint8_t *)&res, sizeof(bt_io_capability_rsp_t));
}
// 弹窗事件
case BT_EVENT_USER_CONFIRM_IND:
{
bt_pair_confirm_t *confirm = (bt_pair_confirm_t *)args->args;
LOG_D("user confirm: %02x%02x%02x%02x%02x%02x", confirm->mac.addr[0], confirm->mac.addr[1], confirm->mac.addr[2],
confirm->mac.addr[3], confirm->mac.addr[4], confirm->mac.addr[5]);
app_send_msg_to_ui_wake(BT_APP, args->event, (uint8_t *)(args->args), sizeof(bt_pair_confirm_t));
}
// BT_EVENT_PAIR_IND 配对应答事件,根据参数判断是成功或失败。
// 当UI端收到此事件时弹出BT配对弹窗,根据用户选择填写对应参数。
send_bt_control_msg_to_app_thread(BT_CONTROL_USER_CONFIRM_RES, (uint8_t *)&res, sizeof(bt_user_confirm_rsp_t));
BT功能配置说明
要关闭BT功能时只需要在HCPU配置“PERI_USING_BT”即可,打开时按功能需求打开对应宏:
名称 |
描述 |
---|---|
PERI_USING_BT |
使能外围设备BT并选择sifli |
BT_FINSH |
使能bt finsh |
BT_METRICS |
使能BT保存数据 |
AUDIO_BT_AUDIO |
使能BT音频 |
然后根据需要的功能打开BT的各个功能,如下图所示:
注:其PAN功能依赖于LWIP,如果不能打开请先打开LWIP功能。
HFP
HFP定义了音频网关(AG)和免提组件(HF)两个角色:
音频网关(AG) – 该设备为音频输入/输出的网关 ,典型作为网关的设备为手机。
免提组件(HF) – 该设备作为音频网关的远程音频输入/输出机制,并可提供若干遥控功能,典型作为免提组件的设备为车机、蓝牙耳机
我们的设备在连接手机时可做为HF,连接TWS耳机时可做为AG,下面对两个角色功能单独介绍。
HF
HF相关控制命令如下:
命令 |
对应函数 |
描述 |
---|---|---|
BT_CONTROL_MAKE_CALL |
app_bt_make_call |
拔打电话 |
BT_CONTROL_PHONE_CONNECT |
app_bt_answer_call |
接听电话 |
BT_CONTROL_PHONE_HANDUP |
app_bt_hang_up |
挂断电话 |
BT_CONTROL_DIAL_BACK |
app_bt_dial_back |
回拔 |
BT_CONTROL_SET_INBAND_RING |
app_bt_set_inband_ring |
设置inband,已在连接成功时调用 |
BT_CONTROL_GET_PHONE_NUMBER |
无 |
获取手机号码,已在连接成功时调用 |
BT_CONTROL_DTMF_DIAL |
app_bt_dtmf_dial |
在通话中输入按键信息 |
BT_CONTROL_GET_SIRI_CAPABILITY |
无 |
获取手机是否支持SIRI,有兼容性问题,未使用 |
BT_CONTROL_SIRI_ON |
app_bt_open_siri |
打开SIRI |
BT_CONTROL_SIRI_OFF |
app_bt_close_siri |
关闭SIRI |
BT_CONTROL_3WAY_HOLD |
app_bt_control_3way_hold |
三方通话操作 |
BT_CONTROL_SET_WBS_STATUS |
app_bt_set_wbs_status |
使能/禁止WBS,测试时使用 |
BT_CONTROL_UPDATE_BATT_BY_HFP |
无 |
向手机发送电池电量值: 0 ~ 9 |
BT_CONTROL_AUDIO_TRANSFER |
app_bt_audio_transfer |
切换音频 |
HF相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_CALL_STATUS_IND |
通话信息(通话状态、号码、ring都在其中) |
BT_EVENT_DIAL_COMPLETE |
拔打电话应答事件,即使是成功了4秒内无通话状态事件通话应用也应按失败处理 |
BT_EVENT_LOCAL_CALL_NUMBER |
手机号码 |
BT_EVENT_CINDS_IND |
HFP连接成功时上报(是否有服务、手机电量、GSM信号强度、是否支持漫游) |
BT_EVENT_CIND_IND |
手机信息发生变化时上报 |
BT_EVENT_AT_CMD_CFM_STATUS |
通话相关AT命令发送结果 |
BT_EVENT_CALL_lINK_ESTABLISHED |
SCO建立 |
BT_EVENT_CALL_LINK_DOWN |
SCO断开 |
BT_EVENT_SIRI_STATE_NOTIFY |
手机端通知的SIRI状态 |
BT_EVENT_SIRI_ON_COMPLETE |
打开SIRI成功 |
BT_EVENT_SIRI_OFF_COMPLETE |
关闭SIRI成功 |
BT_EVENT_SIRI_CAPABILITY_NOTIFY |
SIRI是否支持 |
HF其他接口如下:
/**
* @brief get bt active call state
* @return function execution result @see bt_call_state_t
*/
bt_call_state_t app_bt_get_active_call_state(void);
/**
* @brief get bt call info
* @return function execution result @see bt_call_info_t
*/
bt_call_info_t *app_bt_get_call_info(void);
/**
* @brief get bt call state by idx
* @param[in] idx call idx
* @return function execution result @see bt_call_info_t
*/
bt_call_state_t app_bt_get_call_state_by_idx(uint8_t idx);
/**
* @brief get hfp sco link status
* @retval 0 remote device
* @retval 1 local device
*/
uint8_t app_bt_get_hfp_sco_link(void);
说明:
当通话状态发生改变时都是通过“BT_EVENT_CALL_STATUS_IND”事件上报的,UI端收到此事件时通过“app_bt_get_call_info”函数得到通话信息,通话应用逻辑客户自行处理。
很多有通话功能的第三方APP(如:微信、钉钉等)在通话时,也会有通话信息传到手表,目前我们是屏蔽了第三方APP的通话。
安卓手机是采用特殊号码过滤,不同的安卓手机特殊号码不一样,如有新的特殊号码可添加在"specific_number"数组中。
苹果手机是通过判断手机号码是否有来电号码相同进行屏蔽的。
号码中除了包含’+'号之外,有其他字符都会认为是特殊号码,需特别注意号码中不能有空格(有的厂测机器中号码带空格会导致异常)。
当通话状态发生改变时从HCI看都会有CLCC命令,代码中都会进“bt_call_clcc_hdl"函数进行处理并有相关打印,如通话状态不对可以先查看CLCC中的信息是否正确,其含义如下。
当有三方通话时,CLCC信息有两条,必须通过“BT_CONTROL_3WAY_HOLD”命令进行控制,对应AT指令中CHLD。
有些手机的蓝牙不支持三方通话,但手机做了三方通话功能测试起来就有问题,我们可以通过HCI在连接HFP时查看手机是否支持三方通话,另外手机支持三方通话时如果手机传过来的信息和手机实际上的信息对不上我们也处理不了。
工厂测试时使用的音频盒子或是其他机器可能并不是按标准通话流程进行的,可能会导致在建立sco后被手表主动给断开了,而不能进行测试。为了避免这一现象,需要在进行工厂测试时调用“app_bt_set_audio_switching(SWIITCH_FACTORY_MASK, true);”函数,设置音频处于工厂模式,这时手表端就不会主动去断开esco。
如客户需要将设备端mic采集数据传到手机端,则需要客户在进入对应应用中调用“app_bt_set_audio_switching(SWIITCH_SIRI_MASK, true);”函数,允许手机建立esco,并通过ble发送命令到手机,手机APP收到命令后调用手机建立esco的接口(虚拟通话)来主动建立esco。这时mic的数据就会通过esco传到手机端,手机端APP对数据进行处理。当退出对应应用时要再调用“app_bt_set_audio_switching(SWIITCH_SIRI_MASK, false);”,禁止手机来建立esco。
AG
AG相关控制命令如下:
命令 |
描述 |
---|---|
BT_CONTROL_AG_PHONE_CALL_STATUS_CHANGED |
通话状态发生变化时调用 |
BT_CONTROL_AG_LOCAL_PHONE_INFO_RES |
本机号码 |
BT_CONTROL_AG_REMOTE_CALL_INFO_RES |
当前通话状态 |
BT_CONTROL_AG_ALL_INDICATOR_INFO_RES |
indicator信息 |
BT_CONTROL_AG_INDICATOR_CHANGED_RES |
indicator信息变化 |
BT_CONTROL_AG_SPK_VOL_CHANGE_REQ |
设置扬声器增益 |
BT_CONTROL_AG_MIC_VOL_CHANGE_REQ |
设置麦克风增益 |
BT_CONTROL_AG_CMD_RESULT_RES |
命令回复 |
BT_CONTROL_AUDIO_TRANSFER_EX |
切换音频 |
AG相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_AG_ANSWER_CALL_REQ |
接听电话 |
BT_EVENT_AG_HUNGUP_CALL_REQ |
挂断电话 |
BT_EVENT_MAKE_CALL_REQ |
拔号 |
BT_EVENT_DTMF_KEY_REQ |
DTMF |
BT_EVENT_GET_LOCAL_PHONE_INFO_REQ |
获取本机号码请求事件 |
BT_EVENT_GET_INDICATOR_STATUS_REQ |
获取indicator状态请求事件 |
BT_EVENT_GET_ALL_REMOTE_CALL_INFO_REQ |
获取所有通话信息请求事件 |
A2DP
A2DP相关控制命令如下:
命令 |
函数 |
描述 |
---|---|---|
BT_CONTROL_SET_A2DP_BQB_TEST |
app_bt_set_a2dp_bqb_test |
A2DP BQB测试 |
BT_CONTROL_RELEASE_SET |
app_bt_release_a2dp |
关闭a2dp的音频通路,BQB测试时使用 |
BT_CONTROL_UNREGISTER_AVSINK_SDP |
app_bt_unregister_a2dp_snk_sdp |
注销sink的sdp(手机查询不到A2DP,但设备可以主动连接手机A2DP) |
BT_CONTROL_REGISTER_AVSINK_SDP |
app_bt_register_a2dp_snk_sdp |
注册sink的sdp |
BT_CONTROL_SET_A2DP_SRC_AUDIO_DEVICE |
app_bt_set_a2dp_src_audio_device |
source时切换音频 |
A2DP相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_A2DP_START_IND |
有音频开始传输 |
A2DP切换媒体音频(用于切换媒体音频在手机端还是在手表端)
如要有切换媒体音频在手机端与手表端功能时需要客户在自己的文件中调用“app_bt_enent_register_cb(bt_notify_cb_t cb)”函数注册自己的事件处理函数,然后在BT初始化完成(BT_EVENT_BT_STACK_READY事件)时调用“注销sink的sdp”命令(send_bt_control_msg_to_app_thread(BT_CONTROL_UNREGISTER_AVSINK_SDP, NULL, 0);)。
在进入厂测模式时调用“注册sink的sdp”命令(send_bt_control_msg_to_app_thread(BT_CONTROL_REGISTER_AVSINK_SDP, NULL, 0);)。
/**
* @brief The a2dp function is connect
* @param[in] profile_mask Can multiple profile, example : BT_PROFILE_A2DP_MASK | BT_PROFILE_AVRCP_MASK
* @param[in] enable true:媒体音频在手表端 false:媒体音频在手机端
* @return function execution result @see bt_err_t
*/
bt_err_t app_bt_profile_connect_enable(uint32_t profile_mask, bool enable);
//将媒体音频切换到手表端
app_bt_profile_connect_enable(BT_RPOFILE_A2DP_MASK, true);
//将媒体音频切换到手机端
app_bt_profile_connect_enable(BT_RPOFILE_A2DP_MASK, false);
//如果打开了多连接则此函数会多一个参数,需要传入MAC地址。
//可以获取各个角色最后一次连接的MAC地址。
bt_mac_t app_bt_get_last_slave_addr();
bt_mac_t app_bt_get_last_master_addr();
注:1、A2DP如果连接成功后如没有声音,可以先查看一下音量是为0、a2dp是否打开以及过滤是否是有
AVRCP(音乐信息及控制)
AVRCP相关控制命令如下:
命令 |
函数 |
描述 |
---|---|---|
BT_CONTROL_PHONE_PLAY_PREVIOUS |
app_bt_phone_play_previous |
上一曲 |
BT_CONTROL_PHONE_PLAY_NEXT |
app_bt_phone_play_next |
下一曲 |
BT_CONTROL_PHONE_PLAY |
app_bt_phone_play |
播放 |
BT_CONTROL_PHONE_PLAY_SUSPEND |
app_bt_phone_play_suspend |
暂停 |
BT_CONTROL_PHONE_PLAY_STOP |
app_bt_phone_play_stop |
停止 |
AVRCP相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_MP3_DETAIL_INFO |
MP3详细信息 |
BT_EVENT_MUSIC_TRACK_CHANGED |
TWS控制上一曲、下一曲 |
BT_EVENT_SONG_PLAY_PROGRESS |
歌曲播放进度 |
BT_EVENT_MUSIC_PLAY_STATUS_CHANGED |
播放状态发生变化 |
注:
1. 很多安卓手机绝对音量需要在手机端开启或者不支持绝对音量。
2. IOS没有歌曲播放进度上报,建议IOS使用AMS。
HID(人机接口)
HID相关控制命令如下:
命令 |
描述 |
---|---|
BT_CONTROL_SET_HID_DEVICE |
设置连接手机类型 |
BT_CONTROL_PHONE_DRAG_UP |
上翻页 |
BT_CONTROL_PHONE_DRAG_DOWN |
下翻页 |
BT_CONTROL_PHONE_ONCE_CLICK |
单击 |
BT_CONTROL_PHONE_DOUBLE_CLICK |
双击 |
BT_CONTROL_PHONE_TAKE_PICTURE |
拍照(手机已打开相机此功能才能使用) |
BT_CONTROL_PHONE_VOLUME_UP |
音量加 |
BT_CONTROL_PHONE_VOLUME_DOWN |
音量减 |
SPP
SPP 是 Serial Port Profile(串口协议)的缩写,其定义了使用蓝牙进行 RS232(或类似)串行电缆仿真的设备应使用的协议和过程。简单来说就是在蓝牙设备之间建立虚拟的串口进行数据通信,说白了就是以两个设备间发送自定义数据。我们的SPP支持多通道和多连接
注:IOS不支持SPP协议。
SPP相关控制命令如下:
命令 |
描述 |
---|---|
BT_CONTROL_SEND_SPP_DATA |
发送数据 |
BT_CONTROL_SEND_SPP_RSP |
收到数据后返回应答(不返回应答收不到下一包数据) |
BT_CONTROL_SEND_SPP_DISC_REQ |
断开连接 |
SPP相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_SPP_CONN_IND |
连接成功 |
BT_EVENT_SPP_DATA_IND |
接收数据 |
BT_EVENT_SPP_DATA_CFM |
发送数据成功 |
BT_EVENT_SPP_DISCONN_IND |
断开成功 |
PBAP
Phone Book Access Profile的简称,电话本访问协议,由于手机的电话本太多同步到手表端数据太多,因此采用在通话过程中通过号码去手机端获取联系人的方式。 注:此功能需要在配对时在手机端给予相应的权限。
PBAP相关控制命令如下:
命令 |
描述 |
---|---|
BT_CONTROL_PBAP_SET_PB |
设置获取联系人存储库(连接时已默认设置为手机存储联系人) |
BT_CONTROL_PBAP_GET_NAME_BY_NUMBER |
通过号码获取联系人名称(有通话时已调用) |
PBAP相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_VCARD_LIST_ITEM_NOTIFY |
联系人名称上报(手机端一个号码存为多个名称时会多次上报) |
BT_EVENT_VCARD_LIST_CMP |
本次获取结束(未使用) |
注:PBAP功能只需要打开对应的功能,然后在应用中当有“BT_EVENT_VCARD_LIST_ITEM_NOTIFY”事件上报时就联系人名称显示出来就行。可参考我们的对应代码。
GATT
GATT相关控制命令如下:
命令 |
描述 |
---|---|
BT_CONTROL_BT_GATT_SDP_REG_REQ |
注册 |
BT_CONTROL_BT_GATT_SDP_UNREG_REQ |
取消注册 |
BT_CONTROL_BT_GATT_MTU_CHANGE_REQ |
修改MTU |
GATT相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_BT_GATT_REG_RES |
注册成功 |
BT_EVENT_BT_GATT_UNREG_RES |
取消注册成功 |
BT_EVENT_BT_GATT_MTU_RES |
MTU更新 |
注:GATT需要手机来进行连接,设备端不能主动发起连接
通用功能
相关控制命令如下:
命令 |
函数 |
描述 |
---|---|---|
BT_CONTROL_SEARCH_EQUIPMENT |
app_bt_search_device_start |
搜索设备(TWS) |
BT_CONTROL_CANCEL_SEARCH |
app_bt_search_device_stop |
取消搜索 |
BT_CONTROL_CONNECT_DEVICE |
app_bt_connect_start |
连接 |
BT_CONTROL_CONNECT_DEVICE_EX |
app_bt_connect_start_ex |
连接指定profile |
BT_CONTROL_DISCONNECT |
app_bt_disconnect |
断连所有设备 |
BT_CONTROL_DISCONNECT_EX |
app_bt_disconnect_ex |
断连指定profile |
BT_CONTROL_DISCONNECT_BY_CONNIDX |
app_bt_disconnect_by_conn_idx |
断连指定连接ID |
BT_CONTROL_SET_LOCAL_NAME |
app_bt_set_local_name |
设置BT名称 |
BT_CONTROL_RD_LOCAL_NAME |
无 |
读取BT名称 |
BT_CONTROL_RD_LOCAL_RSSI |
app_bt_get_bt_rssi |
读取RSSI |
BT_CONTROL_SWITCH_OFF |
app_bt_switch_off |
关闭SCAN |
BT_CONTROL_SWITCH_ON |
app_bt_switch_on |
打开SCAN |
BT_CONTROL_SET_SCAN |
app_bt_set_scan |
设置SCAN状态 |
BT_CONTROL_GET_SCAN |
app_bt_get_scan |
获取SCAN状态 |
BT_CONTROL_EXIT_SNIFF |
app_bt_exit_sniff |
退出sniff状态 |
BT_CONTROL_SWITCH_TO_SOURCE |
app_bt_switch_to_source |
切换为source(连接TWS时为此状态) |
BT_CONTROL_SWITCH_TO_SINK |
app_bt_switch_to_sink |
切换为sink(连接手机时为此状态) |
BT_CONTROL_GET_BT_MAC |
app_bt_get_addr |
获取BT的MAC |
BT_CONTROL_GET_VOLUME |
app_bt_get_volume |
获取音量(通过类型区分通话音频、媒体音频) |
BT_CONTROL_SET_VOLUME |
app_bt_set_volume |
设置音量(通过类型区分通话音频、媒体音频) |
BT_CONTROL_GET_PEER_DEVICEINFO |
app_bt_get_peer_deviceinfo |
获取配对设备信息 |
BT_CONTROL_LOCAL_PLAY_NEXT |
app_bt_local_play_next |
本地音乐下一曲 |
BT_CONTROL_LOCAL_PLAY |
app_bt_local_play |
本地音乐播放 |
BT_CONTROL_GET_LOCAL_SONG_DETAILS |
app_bt_get_local_song_detail_info |
获取本地音乐歌曲信息 |
BT_CONTROL_GET_LOCAL_SONG_BRIEF |
app_bt_get_local_song_brief_info |
获取本地音乐简言 |
BT_CONTROL_GET_LOCAL_SONG_TOTAL_NUM |
app_bt_get_local_song_total_num |
获取本地音乐总数量 |
BT_CONTROL_SET_LOCAL_SPK_VOL |
无 |
设置本地音乐音量 |
BT_CONTROL_SET_MIC_MUTE |
app_bt_set_mic_mute |
设置麦克风静音状态 |
BT_CONTROL_GET_MIC_MUTE |
app_bt_get_mic_mute |
获取麦克风静音状态 |
BT_CONTROL_CLOSE_DEVICE |
sned_bt_control_switch_to_app_thread |
关闭BT |
BT_CONTROL_OPEN_DEVICE |
sned_bt_control_switch_to_app_thread |
打开BT |
BT_BQB_TEST_MODE |
无 |
进入BQB测试模式 |
BT_CONTROL_GET_RMT_VERSION |
无 |
获取蓝牙版本信息 |
BT_CONTROL_IO_CAPABILITY_RES |
无 |
配对类型 |
BT_CONTROL_USER_CONFIRM_RES |
无 |
配对弹窗确认 |
BT_CONTROL_AUDIO_TRANSFER_EX |
app_bt_audio_transfer_ex |
切换通话音频(AF和AG都可调用) |
BT_CONTROL_CHANGE_BD_ADDR |
app_bt_change_bd_addr |
更改BT地址 |
BT_CONTROL_CANCEL_PAGE |
app_bt_cancel_page |
取消连接 |
BT_CONTROL_CANCEL_PAGE_BY_ADDR |
app_bt_cancel_page_by_addr |
取消指定地址的连接 |
BT_CONTROL_LOCAL_PLAY_PROMPT_TONE |
app_bt_local_play_prompt_tone |
播放本地提示音 |
BT_CONTROL_PLAY_POWER_ON_RING |
app_bt_play_power_on_ring |
开启循环播放 |
BT_CONTROL_PLAY_POWER_OFF_RING |
app_bt_play_power_off_ring |
关闭开启循环播放 |
BT_CONTROL_GET_RMT_NAME |
app_bt_get_rmt_name |
获取对端蓝牙名称 |
相关事件如下:
事件 |
描述 |
---|---|
BT_EVENT_CALL_LINK_ESTABLISHED |
esco建立结果 |
BT_EVENT_CALL_LINK_DOWN |
esco断开 |
BT_EVENT_INQ |
搜索到的设备 |
BT_EVENT_INQ_FINISHED |
搜索完成 |
BT_EVENT_CONNECT_COMPLETE |
profile连接成功 |
BT_EVENT_PROFILE_DISCONNECT |
profile连接失败或断连 |
BT_EVENT_DISCONNECT |
ACL断连 |
BT_EVENT_KEY_MISSING |
对端取消配对(不用处理,我们发布版代码已做了处理) |
BT_EVENT_ENCRYPTION |
加密 |
BT_EVENT_VOL_CHANGED |
音量变化 |
BT_EVENT_CONTROL_RET |
所有控制事件的结果,通过此事件返回 |
BT_EVENT_POWER_OFF |
BT关闭成功 |
BT_EVENT_BT_STACK_READY |
BT初始化完成 |
BT_EVENT_BT_ADDR_IND |
BT地址上报 |
BT_EVENT_CLOSE_COMPLETE |
关闭完成 |
BT_EVENT_RD_LOCAL_NAME |
BT名称 |
BT_EVENT_RD_LOCAL_RSSI |
RSSI |
BT_EVENT_ACL_OPENED_IND |
ACL连接成功 |
BT_EVENT_PAIR_IND |
配对事件 |
BT_EVENT_CHANGE_BD_ADDR |
修改BT地址的应答 |
BT_EVENT_CANCEL_PAGE_IND |
取消连接的应答 |
BT_EVENT_IO_CAPABILITY_IND |
配对模式 |
BT_EVENT_USER_CONFIRM_IND |
配对确认 |
BT_EVENT_KEY_OVERLAID |
linkkey被覆盖 |
BT_EVENT_SCAN_ENB_CFM |
SCAN状态上报 |
BT_EVENT_RMT_NAME_IND |
对端名称 |
其他接口如下:
/**
* @brief get profile connect state
* @param[in] profile Bluetooth profile
* @return profile connect state @see bt_connect_state_t
* @note Use app_bt_get_profile_state_by_conn_idx after BT_CONNECT_SUPPORT_MULTI_LINK is opened and used
*/
bt_connect_state_t app_bt_get_profile_state(bt_profile_t profile);
/**
* @brief get profile connect state
* @param[in] idx conn index
* @param[in] profile Bluetooth profile
* @return profile connect state @see bt_connect_state_t
*/
bt_connect_state_t app_bt_get_profile_state_by_conn_idx(uint8_t conn_idx, bt_profile_t profile);
/**
* @brief get bt role
* @return role @see bt_role_t
*/
bt_role_t app_bt_get_role(void);
/**
* @brief get acl state
* @return function execution result @see bt_acl_state_t
* @note Use app_bt_get_acl_state_by_conn_idx after BT_CONNECT_SUPPORT_MULTI_LINK is opened and used
*/
bt_acl_state_t app_bt_get_acl_state(void);
/**
* @brief get acl state by conn index
* @param[in] idx conn index
* @return function execution result @see bt_acl_state_t
*/
bt_acl_state_t app_bt_get_acl_state_by_conn_idx(uint8_t conn_idx);
/**
* @brief get bt media state
* @return function execution result @see bt_media_state_t
* @note Use app_bt_get_media_state_by_conn_idx after BT_CONNECT_SUPPORT_MULTI_LINK is opened and used
*/
bt_media_state_t app_bt_get_media_state(void);
/**
* @brief get bt media state by conn index
* @param[in] idx conn index
* @return function execution result @see bt_media_state_t
*/
bt_media_state_t app_bt_get_media_state_by_conn_idx(uint8_t conn_idx);
BT事件自定义处理
请在自己的文件中调用“app_bt_event_register_cb”函数注册一个回调函数对相应的事件处理,在对应的回调函数中自行添加处理逻辑,如对应事件返回值为true则不会执行我们的代码,如返回值为false则我们的代码也会同时执行。
case BT_EVENT_RMT_VERSION_IND:
{
send_msg_to_gui_thread((args->args), sizeof(bt_rmt_version_t), bt_event_process_in_gui_thread_cb, args->event, DONT_NEED_WAKEUP_UI);
}
break;
//例如发布版本的代码中"BT_EVENT_RMT_VERSION_IND"事件只是将信息传送到了UI,客户想保存这个信息,可在客户自己的文件中增加如下代码:
//以下代码在客户自己的文件中。
static bt_rmt_version_t rmt_version = {0};
static bool custom_notify_cb(bt_notify_t *args)
{
uint16_t type = args->event >> 8;
bool ret = false;
switch (args->event)
{
case BT_EVENT_RMT_VERSION_IND:
{
rt_memcpy(&rmt_version, args->args, sizeof(bt_rmt_version_t)); //保存到变量中
ret = true; //返回值为true时,不执行原厂的代码,为false时,会执行原厂的代码
}
break;
default:
break;
}
return ret;
}
app_bt_event_register_cb(custom_notify_cb);
如何进行BT的连接&&回连
连接
在BT处于打开状态时,手机可以搜索并配对连接,但做为手表使用时一般采用一键双链(前面有介绍)。
/**
* @brief send bt control open/close to app thread
* @param[in] cmd BT_CONTROL_OPEN_DEVICE/BT_CONTROL_CLOSE_DEVICE
* @param[in] save 0:do not save 1:save
*/
void send_bt_control_switch_to_app_thread(bt_control_cmd_t cmd, uint8_t save);
注:在打开/关闭BT时不要直接调用app_bt_open/app_bt_close函数,而是调用以上函数进行,否则会出现开关BT时不回连且开关状态不同步的情况。如在测试时需要临时关闭BT请将参数save传0以防止在测试完成后下次开机BT被关闭的情况。
BT连接流程
回连
BT允许设备端发起回连,加上HFP/A2DP等profile存在,回连会更加复杂,下面提到次数的在Solution SDK都是允许修改配置。
拉距或异常断开:这两种场景在设备端都会收到0x08的断连理由,Solution SDK在收到该理由会立刻发起BT连接。如果此时手机不在连接范围,会收到Page timeout(0x04)的连接错误提醒,此时Solution SDK会继续尝试连接,直到连接成功或3次连接都以0x04失败。
设备端重启或设备端关开蓝牙:这两种场景在Solution SDK都会触发回连上一次连接的设备,直到连接成功或3次连接都以0x04失败。
如果场景1和2超时后,Solution SDK不会进行回连。但当BLE被手机连接上后,经过一段时间等待且手机没有发起BT连接,则设备会主动回连上一次连接的设备。
手机主动断开蓝牙,比如关闭手机蓝牙或者在手机设置里面点击断开,这种断开Solution SDK不会发起连接。但可以修改成这种场景也回连,方法为打开“BT_USING_INFINITE_RECONNECT”宏。
如果手机已经取消配对,手表发起连接后会收到LinkKey Missing的错误。这样手表会停止回连并删除该手机的信息。
注:回连BT时如最后一次是耳机测不会进行回连,如果又要连接耳机又要连接手机时当最后一次连接的是耳机时会出现手机ble连接时,不会回连手机的BT。如需要ble连接上时都回连上手机则需要不保存耳机的回连地址。
连接/回连性能
BT连接的速度和Page Scan有关系,但因为手机和设备都有可能发起连接,所以根据谁发起的连接看对方的Page Scan参数。手机端不可设置,都是采用11.25ms窗口/1.28s间隔的配置。
在设备端,SDK提供了默认参数:通常情况下11.25ms的scan 窗口以及1.28s的scan 间隔。如果BLE连接后会修改成22.5ms的窗口以及320ms的间隔,这个只会在BLE连接后的30秒内起作用,timeout或者BT连接上后,都会切换成11.25ms/1.28s。这种配置下,手机基本都可以连接上手表,为了避免环境干扰特别强导致连接失败,手机最好可以在一次连接后,再尝试一次。
当设备端连接手机时,因为手机不会修改参数,所以有些场景可能需要回连1-2次,最差场景回连3次才能连上。默认连接到连接失败(Page timeout)的时间是15秒,正常情况下在5秒内都可以连上,最差可以到30-40秒。
如何通过BT设置&&同步手机音量
当前音量可通过函数"app_bt_volume_db_get()"获取,在设置音量时可以实时保存也可以不保存,当用划动方式调节音量时建议中间设置值不要保存,只在最后一次保存这样可以加快运行速度和提高FLASH寿命。
/**
* @brief get volume information
* @return volume
*/
bt_volume_t *app_bt_volume_db_get(void);
/**
* @brief save volume information
* @param[in] info volume information
*/
void app_bt_volume_db_set(bt_volume_set_t *info);
当手机端调节音量时通过"BT_EVENT_VOL_CHANGED"事件上报手机当前设置的音量值。
注:1. 在设置音量时请使用发送命令的方式(BT_CONTROL_SET_VOLUME),这种方式我们有做处理会有对应的保存。
2. 通话音量只有在sco建立时设置才会有效,其他任何时候设置都不会生效。
3. 设置媒体音频返回值为"BT_ERROR_AVRCP_NO_REG(0x10000011)"时,说明手机端未打开或不支持绝对音量时,如手机端找不到打开绝对音量设置,则表明此手机就是不支持绝对音量,不能使用AVRCP调节媒体音量。
工厂测试音频切换
工厂测试时使用的音频盒子或是其他机器可能并不是按标准通话流程进行的,可能会导致在建立sco后被手表主动给断开了,导致不能进行测试。为了避免这一现象,需要在进行工厂测试时调用“app_bt_set_audio_switching(SWIITCH_FACTORY_MASK, true);”函数,设置音频处于工厂模式,这时手表端就不会主动去断开esco。
常见问题说明
在测试过程中如遇到BT不能回连或是手机不能连接需要首先确认BT是否已打开。
在单连接时连接耳机需要先判断A2DP是否处于允许连接,如处于禁止连接需要先设置为允许连接。