從機(jī)有定義2個(gè)特征值(FF70,FF71)
主機(jī)端代碼中,應(yīng)該怎么處理。
實(shí)現(xiàn)同時(shí)讀取到從機(jī)的2個(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)題~
代碼中請(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ù),
但是藍(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)教
我的項(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)使能
@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)用,不成功。
我在這里復(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)查收。
收到您的郵件了,按照例程代碼做了修改后還是只能開(kāi)啟一個(gè)notify,已經(jīng)將log和代碼回復(fù)到您郵寄了。
已回復(fù)。
我嘗試在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)題,謝謝大佬。