这篇文章的缘由来自于一个需求,就是将手机和手机的配对方式变成,变成手机的和蓝牙音箱的配对方式一样,也就是将一部手机的角色变成和蓝牙音箱一样。
就拿前一篇博文一幅图来说。可以看到pc,手机,蓝牙音箱的图标是不同的,这在前一节里已经说明了,这是由COD字段决定的。
/* Default class of device
* {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS}
*
* SERVICE_CLASS:0x5A (Bit17 -Networking,Bit19 - Capturing,Bit20 -Object Transfer,Bit22 -Telephony)
* MAJOR_CLASS:0x02 - PHONE
* MINOR_CLASS:0x0C - SMART_PHONE
*
*/
#ifndef BTA_DM_COD
#define BTA_DM_COD {0x5A, 0x02, 0x0C}
#endif
如果改成如下的方式,则变成带电话功能的蓝牙音箱了
#define BTA_DM_COD {0x5A, 0x40, 0x08}
这里所描述的配对方式都是SSP方式。
/* bta security callback */
const tBTM_APPL_INFO bta_security =
{
&bta_dm_authorize_cback,
&bta_dm_pin_cback,
&bta_dm_new_link_key_cback,
&bta_dm_authentication_complete_cback,
&bta_dm_bond_cancel_complete_cback,
#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
&bta_dm_sp_cback
#else
NULL
#endif
#if BLE_INCLUDED == TRUE
#if SMP_INCLUDED == TRUE
,&bta_dm_ble_smp_cback
#endif
,&bta_dm_ble_id_key_cback
#endif
注意上面的BTM_IO_CAP_NONE这个很关键的。BTM_LOCAL_IO_CAPS的定义将决定bta_dm_sp_cback,这个函数是SSP的两个分级,如果确实将该函数赋给了上述的bta_security的
/* The IO capability of the local device (for Simple Pairing) */
#ifndef BTM_LOCAL_IO_CAPS
#define BTM_LOCAL_IO_CAPS BTM_IO_CAP_IO
#endif
设备的IO能力会放在如下结构体的最后两个字段,本地和远端设备的能力,上面就是定义本地蓝牙设备IO能力的地方,在配对时,根据IO能力选择相应的能力。
/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */
typedef struct
{
/* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */
BD_ADDR bd_addr; /* peer address */
DEV_CLASS dev_class; /* peer CoD */
BD_NAME bd_name; /* peer device name */
UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */
BOOLEAN just_works; /* TRUE, if "Just Works" association model */
tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */
tBTA_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */
tBTA_IO_CAP loc_io_caps; /* IO Capabilities of local device */
tBTA_AUTH_REQ rmt_io_caps; /* IO Capabilities of remote device */
} tBTA_DM_SP_CFM_REQ;
static int ssp_reply(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant,
uint8_t accept, uint32_t passkey)
{
/* sanity check */
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;
return btif_dm_ssp_reply(bd_addr, variant, accept, passkey);
}
执行SSP确认请求的协议栈函数如下
1054 static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ *p_ssp_cfm_req)
...
if (p_ssp_cfm_req->just_works)
1099 {
...
129 pairing_cb.sdp_attempts = 0;
1130 HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
1131 (p_ssp_cfm_req->just_works ? BT_SSP_VARIANT_CONSENT : BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
1132 p_ssp_cfm_req->num_val);
如果使用的是just work方式,则协议栈自行处理,就不会再弹窗给用户了。如果非just work方式,则ssp_request_cb的参数将是BT_SSP_VARIANT_PASSKEY_CONFIRMATION,从这个定义的名称可以看出,其是需要用户干预(手动确认)的配对方式,如果是BT_SSP_VARIANT_CONSENT,则是同意的方式,这中方式协议栈就处理掉了。一旦选择需要用户确认,那么HAL_CBACK将会回调,经过BondStateMachine最后到安卓的setting里,弹窗提示用户确认配对。
void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p)
为了便于跟踪btm里做了什么事,可以将打印信息的log打开,
+++ b/conf/bt_stack.conf
@@ -26,7 +26,7 @@ TraceConf=true
# BT_TRACE_LEVEL_EVENT 4 ( Debug messages for events )
# BT_TRACE_LEVEL_DEBUG 5 ( Full debug messages )
# BT_TRACE_LEVEL_VERBOSE 6 ( Verbose messages ) - Currently supported for TRC_BTAPP only.
-TRC_BTM=2
+TRC_BTM=5
TRC_HCI=2
TRC_L2CAP=2