参考瓜哥的文档,我这里搬运一下:
七、实验步骤
1、增加多个特征值状态的宏(sImpleBLECentral.c 中)
// Discovery states
enum
{
BLE_DISC_STATE_IDLE, // Idle
BLE_DISC_STATE_SVC, // Service discovery
BLE_DISC_STATE_CHAR1, // Characteristic discovery 1
BLE_DISC_STATE_CHAR2, // Characteristic discovery 2
BLE_DISC_STATE_CHAR3, // Characteristic discovery 3
BLE_DISC_STATE_CHAR4, // Characteristic discovery 4
BLE_DISC_STATE_CHAR5, // Characteristic discovery 5
BLE_DISC_STATE_CHAR6 // Characteristic discovery 6
};
默认的特征值状态的宏只有 BLE_DISC_STATE_CHAR,因此在这里修改为 6 个。(具体要看从
机有几个可读特征值)
2、定义一个自己存放特征句柄的数组(sImpleBLECentral.c 中)
// Discovered characteristic handle
static uint16 simpleBLECharHdl = 0;
static uint16 GUA_charHdl[6] = {0}; //6 个特征值句柄保存位置
当 然 也 可以 直 接修 改 为 simpleBLECharHdl[6],但 这 样需 要 修改 代 码中 其 他用 到
simpleBLECharHdl 的地方。
为了省事,很懒的我自己定义一个 GUA_charHdl[6]。
简单粗暴学蓝牙 4.0(CC2541 篇)
3、修改发现事件的处理函数 simpleBLEGATTDiscoveryEvent(sImpleBLECentral.c 中)
/*********************************************************************
* @fn simpleBLEGATTDiscoveryEvent
*
* @brief Process GATT discovery event
*
* @return none
*/
static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
attReadByTypeReq_t req;
if ( simpleBLEDiscState == BLE_DISC_STATE_SVC )
{
// Service found, store handles
if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0 )
{
simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
}
// If procedure complete
if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete ) ||
( pMsg->method == ATT_ERROR_RSP ) )
{
if ( simpleBLESvcStartHdl != 0 )
{
// Discover characteristic
simpleBLEDiscState = BLE_DISC_STATE_CHAR1;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
}
第 249 页
简单粗暴学蓝牙 4.0(CC2541 篇)
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR1 ) //发现 char1
{
//读出 char1 的 handle 并保存到 GUA_charHdl
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
GUA_charHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
simpleBLEProcedureInProgress = TRUE; //此时仍在进程中
}
//发送命令读取下一个特征值的句柄
else{ //注意这里一定要 else,当
numPairs=0 时才能再读下一个,下同
simpleBLEDiscState = BLE_DISC_STATE_CHAR2;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR2_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR2_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR2 ) //发现 char2
{
//读出 char2 的 handle 并保存到 GUA_charHdl
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
GUA_charHdl[1] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
simpleBLEProcedureInProgress = TRUE; //此时仍在进程中
} 第 250 页
简单粗暴学蓝牙 4.0(CC2541 篇)
//发送命令读取下一个特征值的句柄
else{
simpleBLEDiscState = BLE_DISC_STATE_CHAR4;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
/*
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR3 ) //发现 char3
{
//读出 char3 的 handle 并保存到 GUA_charHdl
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
GUA_charHdl[2] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
simpleBLEProcedureInProgress = TRUE; //此时仍在进程中
}
//发送命令读取下一个特征值的句柄
else{
simpleBLEDiscState = BLE_DISC_STATE_CHAR4;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
*/
第 251 页
简单粗暴学蓝牙 4.0(CC2541 篇)
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR4 ) //发现 char4
{
//读出 char3 的 handle 并保存到 GUA_charHdl
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
GUA_charHdl[3] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
simpleBLEProcedureInProgress = TRUE; //此时仍在进程中
}
//发送命令读取下一个特征值的句柄
else{
simpleBLEDiscState = BLE_DISC_STATE_CHAR6;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
/*
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR5 ) //发现 char5
{
//读出 char3 的 handle 并保存到 GUA_charHdl
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
GUA_charHdl[4] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
simpleBLEProcedureInProgress = TRUE; //此时仍在进程中
}
//发送命令读取下一个特征值的句柄
else{
第 252 页
简单粗暴学蓝牙 4.0(CC2541 篇)
第 253 页
simpleBLEDiscState = BLE_DISC_STATE_CHAR6;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
*/
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR6 ) //发现 char6
{
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
GUA_charHdl[5] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "Char5 Found", HAL_LCD_LINE_6 );
simpleBLEProcedureInProgress = FALSE; //注意最后一个特征值时需要赋
值
}
simpleBLEDiscState = BLE_DISC_STATE_IDLE; //读完最后的 char6,就可以返
回闲置模式了
}
}
注意:
1)主机端只能获得“特征值属性为读、通知,并且属性表中为可读”的特征值句柄。
说的通俗一点,就是特征值的属性要为 GATT_PROP_READ 或 GATT_PROP_NOTIFY,且属性表中
对应的值的属性要为 GATT_PERMIT_READ,主机端才能获取到它的特征值句柄。
例子一:
SimpleBLEPeripheral 工程的 char1 的属性是可读可写(满足条件)
// Simple Profile Characteristic 1 Properties
static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE;
简单粗暴学蓝牙 4.0(CC2541 篇)
属性表中的属性是 GATT_PERMIT_READ(满足条件)
// Characteristic Value 1
{
{ ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
&simpleProfileChar1
},
因此,主机端可获取到同时满足两个条件的 char1 的特征值句柄。
例子二:
SimpleBLEPeripheral 工程的 char3 的属性是可写,不可读(不满足条件)
// Simple Profile Characteristic 3 Properties
static uint8 simpleProfileChar3Props = GATT_PROP_WRITE;
并且属性表中的属性也是 GATT_PERMIT_WRITE(不满足条件)
// Characteristic Value 3
{
{ ATT_BT_UUID_SIZE, simpleProfilechar3UUID },
GATT_PERMIT_WRITE,
0,
&simpleProfileChar3
},
因此,主机端不能获取 char3 的特征值句柄。(如果想获取,需要 char3 修改为
GATT_PROP_READ 和 GATT_PERMIT_READ)
例子三:
SimpleBLEPeripheral 工程的 char4 的属性是通知(满足条件)
// Simple Profile Characteristic 4 Properties
static uint8 simpleProfileChar4Props = GATT_PROP_NOTIFY;
但是属性表中的属性是 0,即不可读不可写(不满足条件)
// Characteristic Value 4
{
{ ATT_BT_UUID_SIZE, simpleProfilechar4UUID },
0,
0,
&simpleProfileChar4
},
因此,主机端不能获取 char4 的特征值句柄。(如果想获取,需要 char4 的属性表修改为
GATT_PERMIT_READ) 2)连续读取特征值句柄时,如果中间某个特征值句柄读取失败,则会导致后续的特征值也
读取不到。
3)char5 的属性表的值的属性是 GATT_PERMIT_AUTHEN_READ,是加密的,需要主机端输入密
第 254 页
简单粗暴学蓝牙 4.0(CC2541 篇)
第 255 页
码后方可读取。