simpleGATTprofile中有5个Characteristic,第4个需要启用通知才能收到,在simpleBLECentral工程中,当启用通知后,是在哪里收到数据?
求各位大神指教。
bamboo:
回复 Yan:
使能通知是向handle为0x002f写入0x0001
gattPrepareWriteReq_t req;
req.handle = 0x002f;
req.len = 2;
req.pValue[0] = 0x00;
req.pValue[1] = 0x01;
req.offset = 0;
GATT_WriteLongCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
但还是无法收到?
Yan:
回复 bamboo:
Hi x,
首先请确定你找的handle是正确的. 这个handle应该是相应的characteristic value的handle的后面一个, 就是characteristic valude的handle加 1 .
另外, 你的 req.pValue 填错了, 上下两个请反一下.
最后, 这里不要用write long, 用一般的写就行, 就两个字节的内容.
下面是个例子:
attWriteReq_t writeReq;
writeReq.handle = 0x002f;
writeReq.len = 2;
writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x01
writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x00
writeReq.sig = 0;
writeReq.cmd = 0;
GATT_WriteCharValue( simpleBLEConnHandle, &writeReq, simpleBLETaskId );
xie weiping:
回复 Yan:
Hi Yan,
notification发送和接收都是在第四通道channel 4吗?
在simpleBLEcenter例子程序里有个按键触发读写的代码:
// Do a read or write as long as no other read or write is in progress if ( simpleBLEDoWrite ) { // Do a write attWriteReq_t req; req.handle = simpleBLECharHdl; req.len = 1; req.value[0] = simpleBLECharVal; req.sig = 0; req.cmd = 0; status = GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId ); }
simpleBLECharHdl 应该是第一通道 channel 1的句柄吧。
req.value[0] = simpleBLECharVal应该是要发送的值。
跟踪发现句柄获得,其中句柄simpleBLECharHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0], pMsg->msg.readByTypeRsp.dataList[1] );
那我该如何获得第四通道数据的句柄?
还有你上面notification的例子怎么是
writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x01
writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x00
notification的要发送的值写在哪里呢?比如我要发送一个数值0xFF,我该怎么用notification发送?
谢谢!
Yan:
回复 xie weiping:
Hi xie,
你说的channel是什么? 第四个channel说的是第四个characteristic?
simpleBLECharHdl这里必须是你对应的characteristic的CCC的那个句柄. CCC指的是Client Characteristic Configuration 的这个descriptor.
CCC句柄一般是在characteristic value的句柄后面.
句柄的顺序是characteristic declaration, characteristic value, 然后是 CCC.
你这个0xFF的value就填写在simpleBLECharVal里面啊.
xie weiping:
回复 Yan:
Hi Yan,
我还是不懂,我说的channel是指
// Profile Parameters#define SIMPLEPROFILE_CHAR1 0 // RW uint8 – Profile Characteristic 1 value #define SIMPLEPROFILE_CHAR2 1 // RW uint8 – Profile Characteristic 2 value#define SIMPLEPROFILE_CHAR3 2 // RW uint8 – Profile Characteristic 3 value#define SIMPLEPROFILE_CHAR4 3 // RW uint8 – Profile Characteristic 4 value#define SIMPLEPROFILE_CHAR5 4 // RW uint8 – Profile Characteristic 4 value
第四个SIMPLEPROFILE_CHAR4 是GATT profile的第四个值,他是一个可以通过通知发送给GATT客户端设备。
在simpleBLEcenter例子程序中有一段按键读写第一个SIMPLEPROFILE_CHAR1的值的代码,如下:
// Do a read or write as long as no other read or write is in progress if ( simpleBLEDoWrite ) { // Do a write attWriteReq_t req; req.handle = simpleBLECharHdl; req.len = 1; req.value[0] = simpleBLECharVal; req.sig = 0; req.cmd = 0; status = GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId ); } else { // Do a read attReadReq_t req; req.handle = simpleBLECharHdl; status = GATT_ReadCharValue( simpleBLEConnHandle, &req, simpleBLETaskId ); }
这段代码很好理解,SIMPLEPROFILE_CHAR1的句柄和value值都在代码中体现了。
但是notification的代码我就很难理解,句柄和value值还有0x01和0x00(
writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x01
writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x00
)
不明白什么意思。
Yan:
回复 xie weiping:
writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x01
writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是 0x00
我之前解释可能有误, 没给你讲清楚.
这两个值目的是打开Notification功能. CCC的参数有两个, 一个Notification, 一个indication. value[0]就是打开关闭notification, value[1]是打开关闭indication.
至于接下来notification发的值是什么, 其实就是对应的characteristic value.
你有空最好去看一下协议栈对spec的定义, 我这样告诉你也只是很少的比较片面的协议栈定义里面的一些内容, 如果你要更好地理解, 最好去看一下spec.
你也可以看上面的教学视频, 也可以看上面的深度培训文档,
最好是可以去blueooth sig 官网上下载spec:
https://www.bluetooth.org/en-us/specification/adopted-specifications
其中第三章 volume 3 Core System Package 里面的 part G: GENERIC ATTRIBUTE PROFILE (GATT) 里面的第三章 3 SERVICE INTEROPERABILITY REQUIREMENTS, 这里面有很详细的介绍 service, characteristic 定义的内容.
里面的 3.3.3.3, 就是Client Characteristic Configuration
xie weiping:
回复 Yan:
好的,非常感谢!
我还想问一下,simpleBLEcenter例子程序中,有个simpleBLECharHdl 句柄的获得,这个句柄应该是SIMPLEPROFILE_CHAR1的句柄吧
simpleBLECharHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0], pMsg->msg.readByTypeRsp.dataList[1] );
这段什么意思呢?dataList[0],dataList[1]代表什么?假如我想获得其他SIMPLEPROFILE_CHAR的句柄该如何获得呢?比如SIMPLEPROFILE_CHAR2、SIMPLEPROFILE_CHAR3等。
谢谢!
Yan:
回复 xie weiping:
是的.
如果你仔细看代码, 就应该不难看出, 这里有个状态机.
前面的状态里面的代码:
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID); req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
就是用来查找SIMPLEPROFILE_CHAR1的句柄的.
你贴的代码就是状态机进入到找到这个句柄后的状态.
dagaList, 你如果也仔细看代码的话, 这个就是peripheral那边回复过来的具体数据, 这里就是句柄.
如果你要查找SIMPLEPROFILE_CHAR2,或者SIMPLEPROFILE_CHAR3, 你可以简单替换掉前面状态机里面(就是我上面贴的代码)的查找参数.
更好的方法是你在原先的状态机里面多添加几个状态, 在查找玩CHAR1之后添加查找CHAR2, CHAR3, 等等. 也很方便, 不难.
bamboo:
回复 Yan:
在收到CHAR1的handle后立刻查找其他特征值的handle,会找不到
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR )
{
。。。
//simpleBLEDiscState = BLE_DISC_STATE_IDLE;
接着查找
if ( simpleBLESvcStartHdl != 0 )
{
// Discover characteristic 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 );
LCD_WRITE_STRING( "Finding", HAL_LCD_LINE_1 );
}
}
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR6 )
{
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 )
{
simpleBLECharHd6 = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "CHAR6 Found", HAL_LCD_LINE_1 );
}
simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
如果不马上查找就可以,请问是哪里有问题?