Part Number: LAUNCHXL-CC26X2R1
Hi all!
So I don't want you guys to get bored, so I have a new question :-)
In the past Simple Link Academy has been a massive help, but I did notice in the last days, that the information of using simple_central / multi_role as a GATT Client is very minimal. Therefor I do have some questions and yes I read chapter "Generic Attribute Profile (GATT)" and "ATT and GATT Introduction" multiple times, but I'm still stuck with the following question and problem.
1. When I use 2 multi_role devices that advertise and scan Simultaneously and connect to each other, how can I check which device is the Gatt Client and which the Gatt Server in this particular connection.
2. Without knowing how to solve no. 1 I try to write as a GATT Client to the GATT Server to a custom profile and I always get as a return "Write Error 1" when using GATT_WriteCharValue(), Here is my code where I try to write the Value to a custom profile after I press a button:
status_t status7; uint8_t charVals[4] = { 0x04, 0x04, 0x04, 0x04 }; // Should be consistent with // those in scMenuGattWrite attWriteReq_t req; req.pValue = GATT_bm_alloc(connHandle2, ATT_WRITE_REQ, 1, NULL); if ( req.pValue != NULL ) { uint8_t connIndex = multi_role_getConnIndex(connHandle2); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); req.handle = connList[connIndex].charHandle; req.len = 1; charVal = charVals[1]; req.pValue[0] = charVal; req.sig = 0; req.cmd = 0; status7 = GATT_WriteCharValue(connHandle2, &req, selfEntity); if ( status7 != SUCCESS ) { GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ); }else { Display_printf(dispHandle, MR_ROW_MYADDRSS, 0, "Write Request Sent to connhandle %i", connHandle2); } }
This Is my multi_role_processGATTDiscEvent:
static void multi_role_processGATTDiscEvent(gattMsgEvent_t *pMsg) { uint8_t connIndex = multi_role_getConnIndex(pMsg->connHandle); MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); if (connList[connIndex].discState == BLE_DISC_STATE_MTU) { // MTU size response received, discover Custom service if (pMsg->method == ATT_EXCHANGE_MTU_RSP) { uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(CUSTOMSERVICE_SERV_UUID), HI_UINT16(CUSTOMSERVICE_SERV_UUID) }; connList[connIndex].discState = BLE_DISC_STATE_SVC; // Discovery Custom service VOID GATT_DiscPrimaryServiceByUUID(pMsg->connHandle, uuid, ATT_BT_UUID_SIZE, selfEntity); } } else if (connList[connIndex].discState == BLE_DISC_STATE_SVC) { // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); } // If procedure complete if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) && (pMsg->hdr.status == bleProcedureComplete)) || (pMsg->method == ATT_ERROR_RSP)) { if (svcStartHdl != 0) { attReadByTypeReq_t req; // Discover characteristic connList[connIndex].discState = BLE_DISC_STATE_CHAR; req.startHandle = svcStartHdl; req.endHandle = svcEndHdl; req.type.len = ATT_BT_UUID_SIZE; req.type.uuid[0] = LO_UINT16(CUSTOM_SERV6_UUID); req.type.uuid[1] = HI_UINT16(CUSTOM_SERV6_UUID); VOID GATT_DiscCharsByUUID(pMsg->connHandle, &req, selfEntity); } } } else if (connList[connIndex].discState == BLE_DISC_STATE_CHAR) { // Characteristic found, store handle if ((pMsg->method == ATT_READ_BY_TYPE_RSP) && (pMsg->msg.readByTypeRsp.numPairs > 0)) { uint8_t connIndex = multi_role_getConnIndex(connHandle2); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); // Store the handle of the QW characteristic 1 value connList[connIndex].charHandle = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[3], pMsg->msg.readByTypeRsp.pDataList[4]); Display_printf(dispHandle, 13, 0, "Custom Svc Found"); // Now we can use GATT Read/Write tbm_setItemStatus(&mrMenuPerConn, MR_ITEM_GATTREAD | MR_ITEM_GATTWRITE, MR_ITEM_NONE); } connList[connIndex].discState = BLE_DISC_STATE_IDLE; } }
This is my multi_role_processGATTMsg
static uint8_t multi_role_processGATTMsg(gattMsgEvent_t *pMsg) { // Get connection index from handle uint8_t connIndex = multi_role_getConnIndex(pMsg->connHandle); MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT) { // ATT request-response or indication-confirmation flow control is // violated. All subsequent ATT requests or indications will be dropped. // The app is informed in case it wants to drop the connection. // Display the opcode of the message that caused the violation. Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); } else if (pMsg->method == ATT_MTU_UPDATED_EVENT) { // MTU size updated Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); } // Messages from GATT server if (linkDB_Up(pMsg->connHandle)) { if ((pMsg->method == ATT_READ_RSP) || ((pMsg->method == ATT_ERROR_RSP) && (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ))) { if (pMsg->method == ATT_ERROR_RSP) { Display_printf(dispHandle, SP_NVS_DEBUG, 0, "Read Error %d", pMsg->msg.errorRsp.errCode); } else { // After a successful read, display the read value Display_printf(dispHandle, SP_NVS_DEBUG, 0, "Read rsp: %d", pMsg->msg.readRsp.pValue[0]); } } else if ((pMsg->method == ATT_WRITE_RSP) || ((pMsg->method == ATT_ERROR_RSP) && (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ))) { if (pMsg->method == ATT_ERROR_RSP) { Display_printf(dispHandle, 0, SP_NVS_DEBUG, "Write Error %d", pMsg->msg.errorRsp.errCode); } else { // After a succesful write, display the value that was written and // increment value Display_printf(dispHandle, SP_NVS_DEBUG, 0, "Write sent: %d", charVal); } tbm_goTo(&mrMenuPerConn); } else if (connList[connIndex].discState != BLE_DISC_STATE_IDLE) { multi_role_processGATTDiscEvent(pMsg); } } // Else - in case a GATT message came after a connection has dropped, ignore it. // Free message payload. Needed only for ATT Protocol messages GATT_bm_free(&pMsg->msg, pMsg->method); // It's safe to free the incoming message return (TRUE); }
If I write a 0x04 to the characteristic Value CUSTOM_SERV6_UUID via the SimpleLink iOS app it works perfectly, but not if I do it from the multi_role -> multi_role.
I'm pretty sure I have a mistake there, I noticed that everything is very well explained, but I think the information how a GATT Client operates is very minimal and the past questions in the forum are not a big help.
Thanks in advance.
Kind Regards,
SPEEDBIRD