主機(jī)如何同時(shí)監(jiān)聽(tīng)多個(gè)特征值

從機(jī)有定義2個(gè)特征值(FF70,FF71)

主機(jī)端代碼中,應(yīng)該怎么處理。

實(shí)現(xiàn)同時(shí)讀取到從機(jī)的2個(gè)特征值呢。


首先,要區(qū)分 "監(jiān)聽(tīng)"跟 "讀取" 的差異,

一般來(lái)說(shuō)ble 外設(shè)設(shè)備或者說(shuō)從機(jī)(通常作為server)的數(shù)據(jù)傳給主機(jī)(通常為有兩種方式:

1, 從機(jī)主動(dòng)上報(bào)包括notify或indicate;

2, 主機(jī)端去讀,這時(shí)候主動(dòng)權(quán)在主機(jī)側(cè),而不是從機(jī)側(cè).


這里我們先來(lái)討論下,notify

實(shí)現(xiàn)notify的前提是, 主機(jī)端先對(duì)從機(jī)使能cccd, 然后從機(jī)端才可以notify 數(shù)據(jù)出來(lái),這里我們就要解決使能notify的問(wèn)題:

實(shí)際上cccd 對(duì)應(yīng)的uuid 是 0x2902

我們根據(jù)primary service 查到的handle區(qū)間, 再去通過(guò)GATT_ReadUsingCharUUID查到cccd對(duì)應(yīng)的handle即可:

attReadByTypeReq_t?req;
req.startHandle?=?centralSvcStartHdl;
req.endHandle?=?centralSvcEndHdl;
req.type.len?=?ATT_BT_UUID_SIZE;
req.type.uuid[0]?=?LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
req.type.uuid[1]?=?HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
result?=?GATT_ReadUsingCharUUID(?centralConnHandle,?&req,?centralTaskId?);


然后在gatt_discivery的事件里面 去把發(fā)現(xiàn)的所有的具有cccd的handle 記錄下來(lái):

?????case?BLE_DISC_STATE_CCCD:
?????????if?(?pMsg->method?==?ATT_READ_BY_TYPE_RSP)?{
????????????if(pMsg->msg.readByTypeRsp.numPairs?>?0?)?{?????????????????
?????????????????centralCCCDHdl?=?BUILD_UINT16(?pMsg->msg.readByTypeRsp.pDataList[0],
?????????????????????????????????????????????pMsg->msg.readByTypeRsp.pDataList[1]?);
????????????????????for(unsigned?char?i?=?0;?i?<?pMsg->msg.readByTypeRsp.numPairs?;?i++){?????????????????????????
????????????????????????????char_value_handle_list[cccd_handle_index++]?=?BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[pMsg->msg.readByTypeRsp.len?*?i],?\
????????????????????????????????????????????????????????????pMsg->msg.readByTypeRsp.pDataList[pMsg->msg.readByTypeRsp.len?*?i+1]);???
????????????????????}?????????????
????????????}
????????????ble_db_dis_state?=?BLE_DISC_STATE_IDLE;
????????}


然后再把char_value_handle_list[cccd_handle_index++] 里面存儲(chǔ)的cccd handle 依次使能:

? ?

??????uint8_t?data[2]?=?{0x01,0x00};
????return?central_gatt_write_char_value(connection_handle,notify_handle,data,2);

其中:

uint8_t?central_gatt_write_char_value(uint16_t?connection_handle,uint16_t?char_handle,uint8_t?*data,uint16_t?length){
????uint8_t?result;
????attWriteReq_t?req;
?
????req.cmd?=?FALSE;
????req.sig?=?FALSE;
????req.handle?=?char_handle;
????req.len?=?length;
????req.pValue?=?GATT_bm_alloc(connection_handle,ATT_WRITE_REQ,req.len,NULL,0);
????if?(?req.pValue?!=?NULL?){
????????tmos_memcpy(req.pValue,data,length);?
????????result?=?GATT_WriteCharValue(centralConnHandle,&req,centralTaskId);
????????if(SUCCESS?==?result){
????????????return?SUCCESS;
????????}else{
????????????GATT_bm_free((gattMsg_t?*)&req,?ATT_WRITE_REQ);
????????????write_data_when_failed.connection_handle?=?connection_handle;
????????????write_data_when_failed.char_handle?=?char_handle;
????????????write_data_when_failed.data_length?=?length;
????????????tmos_memcpy(write_data_when_failed.data,data,write_data_when_failed.data_length);
????????????PRINT("data0?data1=%02x?%02x?\r\n",write_data_when_failed.data[0],write_data_when_failed.data[1]);
????????????tmos_start_task(centralTaskId,START_WRITE_EVT,80);
????????????return?result;
????????}
????}
????return?0xff;
}

經(jīng)過(guò)使能cccd 后,就可以在

GATT的event 里面下面類似的處理函數(shù)內(nèi),接收到 notify數(shù)據(jù)了

static?void?centralProcessGATTMsg(?gattMsgEvent_t?*pMsg?){
????if?(?centralState?!=?BLE_STATE_CONNECTED?){
????????//?In?case?a?GATT?message?came?after?a?connection?has?dropped,
????????//?ignore?the?message
????????return;
????}
????
????switch(pMsg->method){
????????case?ATT_HANDLE_VALUE_NOTI:
????????????PRINT("ATT_HANDLE_VALUE_NOTI->");
????????????for(uint16_t?i=0;imsg.handleValueNoti.len;i++){
????????????????PRINT("%02X?",pMsg->msg.handleValueNoti.pValue[i]);
????????????}
????????????PRINT("\r\n");


至于read

這里是類似上面的查詢cccd的handle,需要依次,把char value 的handle 查到,,然后根據(jù)對(duì)應(yīng)的handle,調(diào)用

extern bStatus_t GATT_ReadCharValue( uint16 connHandle, attReadReq_t *pReq, uint8 taskId );

然后在 GATT的event 里面下面類似的處理函數(shù)內(nèi),

接收到ATT_READ_RSP的值:

static?void?centralProcessGATTMsg(?gattMsgEvent_t?*pMsg?){
????if?(?centralState?!=?BLE_STATE_CONNECTED?){
????????//?In?case?a?GATT?message?came?after?a?connection?has?dropped,
????????//?ignore?the?message
????????return;
????}
????
????switch(pMsg->method){
????????case?ATT_READ_RSP:
????????????PRINT("接收到ATT_READ_RSP的值->");
????????????for(uint16_t?i=0;imsg.readRsp.len;i++){
????????????????PRINT("%02X?",pMsg->msg.readRsp.pValue[i]);
????????????}
????????????PRINT("\r\n");



非常感謝??

已經(jīng)解決了


????????attReadReq_t?req;??
????????
????????req.handle?=?centralCharHdl;///讀取不同的特征值數(shù)據(jù)????????
????????if(?GATT_ReadCharValue(?centralConnHandle,?&req,?centralTaskId?)?==?SUCCESS?)
????????{
??????????centralProcedureInProgress?=?TRUE;
??????????centralDoWrite?=?!centralDoWrite;
????????}
????if?(?(?pMsg->method?==?ATT_READ_RSP?)?||
???????(?(?pMsg->method?==?ATT_ERROR_RSP?)?&&
?????????(?pMsg->msg.errorRsp.reqOpcode?==?ATT_READ_REQ?)?)?)
??{
????if?(?pMsg->method?==?ATT_ERROR_RSP?)
????{
??????uint8?status?=?pMsg->msg.errorRsp.errCode;
??????
??????PRINT(?"Read?Error:?%x\n",?status?);
????}
????else
????{
??????//?After?a?successful?read,?display?the?read?value
??????PRINT("Read?rsp:?%x\n",*pMsg->msg.readRsp.pValue);
??????////這里如何判斷數(shù)據(jù)來(lái)源呢?是由哪個(gè)特征值返回的數(shù)據(jù)呢。
????}
????centralProcedureInProgress?=?FALSE;
??}


新的問(wèn)題~j_0035.gif

代碼中請(qǐng)求讀取3個(gè)不同特征值的數(shù)據(jù)

在event(ATT_READ_RSP)中? ,如何區(qū)分返回?cái)?shù)據(jù)的來(lái)源呢。



wch的協(xié)議棧中, read rsp 并沒(méi)有帶除了數(shù)據(jù)和長(zhǎng)度以外的數(shù)據(jù)

/**
?*?Read?Response?format.
?*/
typedef?struct
{
??uint16?len;????//!<?Length?of?value
??uint8?*pValue;?//!<?Value?of?the?attribute?with?the?handle?given?(0?to?ATT_MTU_SIZE-1)
}?attReadRsp_t;

而在規(guī)范里,亦沒(méi)有帶,

在Read Response 中并沒(méi)有攜帶 handle之類的數(shù)據(jù),

image.png


但是藍(lán)牙的協(xié)議規(guī)范在一個(gè)讀沒(méi)完成之前, 不允許發(fā)另外一個(gè)讀.


所以,你可以做個(gè)標(biāo)志位, gatt read request 的時(shí)候,把要read的handle記錄下來(lái),這樣在gatt read rsp 事件來(lái)的時(shí)候,就對(duì)應(yīng)的handle 過(guò)來(lái)的數(shù)據(jù).


嗯嗯,我在特征值數(shù)據(jù)中做了區(qū)分??梢哉^(qū)分?jǐn)?shù)據(jù)來(lái)源了。


還有問(wèn)題需要請(qǐng)教j_0070.gif

我的項(xiàng)目中將CH573作為主機(jī),需要比較頻繁讀取從機(jī)的特征值數(shù)據(jù)(3個(gè)),還要能隨時(shí)寫(xiě)入一個(gè)特征值。經(jīng)常會(huì)出現(xiàn)讀取失敗或者寫(xiě)失敗的情況。

請(qǐng)問(wèn)有什么解決方案和優(yōu)化的方法嗎。

3個(gè)特征值的讀取間隔 分別是300ms? 1000ms? 3000ms ,使用主機(jī)循環(huán)讀取特征值還是從機(jī)發(fā)送notify的方式會(huì)更好一點(diǎn)呢?



建議使用notify, notify 的效率更高且?guī)Я薵att handle.只是需要在連接時(shí)候依次寫(xiě)cccd, 使能notify.

而read request 需要在至少兩個(gè)連接事件才能完成一個(gè)過(guò)程,

而notify 可以做到一個(gè)連接事件notify 多個(gè)數(shù)據(jù). (config.h 中的 BLE_TX_NUM_EVENT 大于1 即可.)



你好,TECH46。您解答的完整的例子能發(fā)一份嗎?


請(qǐng)問(wèn)一下,使用開(kāi)啟兩個(gè)特征值的notify功能代碼應(yīng)該怎么寫(xiě),我目前是在開(kāi)啟了CCCD之后,又仿照例子增加了查找特征值2,開(kāi)啟CCCD的順序,但是收到的notify值依舊只是第一個(gè)特征值的notify。

static?void?centralGATTDiscoveryEvent(gattMsgEvent_t?*pMsg)?{
????attReadByTypeReq_t?req;
????if?(centralDiscState?==?BLE_DISC_STATE_SVC)?{
????????//?Service?found,?store?handles
????????if?(pMsg->method?==?ATT_FIND_BY_TYPE_VALUE_RSP
????????????????&&?pMsg->msg.findByTypeValueRsp.numInfo?>?0)?{
????????????centralSvcStartHdl?=?ATT_ATTR_HANDLE(
????????????????????pMsg->msg.findByTypeValueRsp.pHandlesInfo,?0);
????????????centralSvcEndHdl?=?ATT_GRP_END_HANDLE(
????????????????????pMsg->msg.findByTypeValueRsp.pHandlesInfo,?0);

????????????//?Display?Profile?Service?handle?range
????????????PRINT("Found?Profile?Service?handle?:?%x?~?%x?\n",
????????????????????centralSvcStartHdl,?centralSvcEndHdl);
????????}
????????//?If?procedure?complete
????????if?((pMsg->method?==?ATT_FIND_BY_TYPE_VALUE_RSP
????????????????&&?pMsg->hdr.status?==?bleProcedureComplete)
????????????????||?(pMsg->method?==?ATT_ERROR_RSP))?{
????????????if?(centralSvcStartHdl?!=?0)?{

????????????????//?Discover?characteristic
????????????????centralDiscState?=?BLE_DISC_STATE_CHAR1;
????????????????req.startHandle?=?centralSvcStartHdl;
????????????????req.endHandle?=?centralSvcEndHdl;
????????????????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);
????????????????printf("S-CHAR1\r\n");
//????????????????GATT_ReadUsingCharUUID(centralConnHandle,?&req,?centralTaskId);
????????????????GATT_DiscCharsByUUID(centralConnHandle,?&req,?centralTaskId);
????????????}
????????}

????}?else?if?(centralDiscState?==?BLE_DISC_STATE_CHAR1)?{
????????//?Characteristic?found,?store?handle
????????if?(pMsg->method?==?ATT_READ_BY_TYPE_RSP
????????????????&&?pMsg->msg.readByTypeRsp.numPairs?>?0)?{

????????????centralCharHdl?=?BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
????????????????????pMsg->msg.readByTypeRsp.pDataList[1]);

????????????//?Start?do?read?or?write
????????????/*
?????????????tmos_start_task(centralTaskId,?START_READ_OR_WRITE_EVT,
?????????????DEFAULT_READ_OR_WRITE_DELAY);
?????????????*/

????????????//?Display?Characteristic?1?handle
????????????PRINT("Found?Characteristic?1?handle?:?%x?\n",?centralCharHdl);
????????}
????????if?((pMsg->method?==?ATT_READ_BY_TYPE_RSP
????????????????&&?pMsg->hdr.status?==?bleProcedureComplete)
????????????????||?(pMsg->method?==?ATT_ERROR_RSP))?{
????????????//?Discover?characteristic
????????????centralDiscState?=?BLE_DISC_STATE_CCCD1;
????????????req.startHandle?=?centralSvcStartHdl;
????????????req.endHandle?=?centralSvcEndHdl;
????????????req.type.len?=?ATT_BT_UUID_SIZE;
????????????req.type.uuid[0]?=?LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
????????????req.type.uuid[1]?=?HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
????????????printf("M-CHAR1\r\n");
????????????GATT_ReadUsingCharUUID(centralConnHandle,?&req,?centralTaskId);
????????}
????}?else?if?(centralDiscState?==?BLE_DISC_STATE_CCCD1)?{
????????printf("DDDD,%x\r\n",?pMsg->msg.readByTypeRsp.numPairs);
????????//?Characteristic?found,?store?handle
????????if?(pMsg->method?==?ATT_READ_BY_TYPE_RSP
????????????????&&?pMsg->msg.readByTypeRsp.numPairs?>?0)?{
????????????centralCCCDHdl?=?BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
????????????????????pMsg->msg.readByTypeRsp.pDataList[1]);


????????????//?Start?do?write?CCCD
????????????tmos_start_task(centralTaskId,?START_WRITE_CCCD_EVT,
????????????DEFAULT_WRITE_CCCD_DELAY);
????????????printf("F-CHAR1\r\n");

????????????//?Display?Characteristic?1?handle
????????????PRINT("Found?client?characteristic?configuration?handle?:?%x?\n",
????????????????????centralCCCDHdl);
????????}
????????//?If?procedure?complete
????????if?((pMsg->method?==?ATT_READ_BY_TYPE_RSP
????????????????&&?pMsg->hdr.status?==?bleProcedureComplete)
????????????????||?(pMsg->method?==?ATT_ERROR_RSP))?{
????????????//?Discover?characteristic
????????????centralDiscState?=?BLE_DISC_STATE_CHAR2;
????????????req.startHandle?=?centralSvcStartHdl;
????????????req.endHandle?=?centralSvcEndHdl;
????????????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);
????????????printf("S-CHAR2\r\n");
//????????????????GATT_ReadUsingCharUUID(centralConnHandle,?&req,?centralTaskId);
????????????GATT_DiscCharsByUUID(centralConnHandle,?&req,?centralTaskId);
????????}
????}?else?if?(centralDiscState?==?BLE_DISC_STATE_CHAR2)?{
????????//?Characteristic?found,?store?handle
????????if?(pMsg->method?==?ATT_READ_BY_TYPE_RSP
????????????????&&?pMsg->msg.readByTypeRsp.numPairs?>?0)?{
????????????centralCharHdl?=?BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
????????????????????pMsg->msg.readByTypeRsp.pDataList[1]);

????????????//?Start?do?read?or?write
????????????/*
?????????????tmos_start_task(centralTaskId,?START_READ_OR_WRITE_EVT,
?????????????DEFAULT_READ_OR_WRITE_DELAY);
?????????????*/

????????????//?Display?Characteristic?1?handle
????????????PRINT("Found?Characteristic?1?handle?:?%x?\n",?centralCharHdl);
????????}
????????if?((pMsg->method?==?ATT_READ_BY_TYPE_RSP
????????????????&&?pMsg->hdr.status?==?bleProcedureComplete)
????????????????||?(pMsg->method?==?ATT_ERROR_RSP))?{
????????????//?Discover?characteristic
????????????centralDiscState?=?BLE_DISC_STATE_CCCD2;
????????????req.startHandle?=?centralSvcStartHdl;
????????????req.endHandle?=?centralSvcEndHdl;
????????????req.type.len?=?ATT_BT_UUID_SIZE;
????????????req.type.uuid[0]?=?LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
????????????req.type.uuid[1]?=?HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
????????????printf("M-CHAR2\r\n");
????????????GATT_ReadUsingCharUUID(centralConnHandle,?&req,?centralTaskId);
????????}
????}?else?if?(centralDiscState?==?BLE_DISC_STATE_CCCD2)?{
????????printf("DDDD,%x\r\n",?pMsg->msg.readByTypeRsp.numPairs);
????????//?Characteristic?found,?store?handle
????????if?(pMsg->method?==?ATT_READ_BY_TYPE_RSP
????????????????&&?pMsg->msg.readByTypeRsp.numPairs?>?0)?{
????????????printf("IIII\r\n");
????????????centralCCCDHdl?=?BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
????????????????????pMsg->msg.readByTypeRsp.pDataList[1]);
????????????centralProcedureInProgress?=?FALSE;

????????????//?Start?do?write?CCCD
????????????tmos_start_task(centralTaskId,?START_WRITE_CCCD_EVT,
????????????DEFAULT_WRITE_CCCD_DELAY);
????????????printf("F-CHAR2\r\n");
????????????//?Display?Characteristic?1?handle
????????????PRINT("Found?client?characteristic?configuration?handle?:?%x?\n",
????????????????????centralCCCDHdl);
????????}
????????centralDiscState?=?BLE_DISC_STATE_IDLE;
????}
}



應(yīng)該是第二個(gè)沒(méi)使能


image.png


@xhh,謝謝大佬,道理我懂的,第2個(gè)的centralCCDHdl可以在這里拿,但是他這里提交了一個(gè)start_cccd_evt之后,必須要等返回了成功寫(xiě)入了之后才能進(jìn)行第2個(gè)的操作,這里我就不清楚在哪個(gè)回調(diào)函數(shù)里面提交第二個(gè)服務(wù)的cccd了。

我嘗試了在你上面截圖這里再拿一個(gè)cccdHdl1,然后在start_write_cccd_evt里面調(diào)用,不成功。

image.png

我在這里復(fù)制了一遍,改成了CCCDHdl1,也是不成功的


@TECH_Lpc

大佬能不能幫忙看下代碼怎么寫(xiě)


你好,例程是獲取一個(gè)cccd對(duì)應(yīng)的handle值,如果從機(jī)擁有多個(gè)noti,則主機(jī)可以依次獲取對(duì)應(yīng)的cccd并進(jìn)行使能。針對(duì)該功能提供了一份可以獲取到所有屬性的代碼參考。已發(fā)送至郵箱,請(qǐng)查收。


@TECH_Lpc

收到您的郵件了,按照例程代碼做了修改后還是只能開(kāi)啟一個(gè)notify,已經(jīng)將log和代碼回復(fù)到您郵寄了。


已回復(fù)。


@TECH_Lpc

我嘗試在notify的回調(diào)函數(shù)中開(kāi)啟第2個(gè)服務(wù)的notify,而后發(fā)現(xiàn)log里面出現(xiàn)Param Update...,查看代碼得知這是GAP_LINK_PARAM_UPDATE_EVENT事件引起的。同時(shí)第一個(gè)已經(jīng)開(kāi)啟的notify關(guān)閉了,第2個(gè)服務(wù)的notify開(kāi)啟了。

看這個(gè)事件的名字是連接參數(shù)更改?

請(qǐng)問(wèn)這個(gè)信息能否幫忙定位一下問(wèn)題,謝謝大佬。


只有登錄才能回復(fù),可以選擇微信賬號(hào)登錄

国产91精品新入口,国产成人综合网在线播放,九热这里只有精品,本道在线观看,美女视频a美女视频,韩国美女激情视频,日本美女pvp视频