Tool/software:
Hi,
Chipset: CC2340R5
sdk:
Hi I am currently using one CC2340R5 EVK (Central EVK)for development and I am running the EVK in central role, Basic ble sdk is used as a base project.
I am using another CC2340R5 EVK(Peripheral EVK) in peripheral mode, the basic ble sdk code is used as a base project.
I have The gatt table of the evk running in peripheral role using nrf connect and it is attached below. After collecting this info, I disconnect the peripheral device from nRF connect.
Now, using the "Central EVK" I connect to the "Peripheral EVK". After the connection is successful, I initiate a service discovery call as shown below:
I have used the Log_printf function to print the response for the service discovery, and it is as follows:
I have saved the service discovery response in a queue.
Later, I call retrieve the service discovery response from the queue and call the "GATT_DiscAllChars" APIas shown below.
I get a "ATT_READ_BY_GRP_TYPE_RSP" rsp and after parsing, I have printed the contents of " attReadByGrpTypeRsp_t" below.
as you can see, the dataLen field contains a very huge number.
What could be the issue here? I am not able to proceed further due to this, Please help me resolve this.
In addition, I have also added the logic that I have used to parse the "attReadByGrpTypeRsp_t" structure.
Hello,
You shouldn't be getting an ATT_READ_BY_GRP_TYPE_RSP, since GATT_DiscAllChars returns ATT_READ_BY_TYPE_RSP which uses a different structure.
Are you receiving ATT_READ_BY_GRP_TYPE_RSP instead of ATT_READ_BY_TYPE_RSP? Do you mind sending over your handler code so I can review it?
Best,
Nima Behmanesh
Hi Nima,
Thanks for pointing out the mistake. I posted the wrong snippets. Please find my GATT_EvenHandler below.
static void GATT_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData) { gattMsgEvent_t *gattMsg = ( gattMsgEvent_t * )pMsgData; switch ( gattMsg->method ) { case ATT_FLOW_CTRL_VIOLATED_EVENT: { MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT status: ATT flow control is violated"); } break; case ATT_MTU_UPDATED_EVENT: { MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT status: ATT MTU update to %d", gattMsg->msg.mtuEvt.MTU); Log_printf(LogModule_App1, Log_INFO, "MTU updated to: %d", gattMsg->msg.mtuEvt.MTU); } break; case ATT_READ_BY_GRP_TYPE_RSP: { MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT status: ATT MTU update to %d", gattMsg->msg.mtuEvt.MTU); attReadByGrpTypeRsp_t *resp = (attReadByGrpTypeRsp_t *)&(gattMsg->msg.readByGrpTypeRsp); Log_printf(LogModule_App1, Log_INFO, "response len: %d", resp->len); Log_printf(LogModule_App1, Log_INFO, "num groups: %d", resp->numGrps); if(resp->len) { sendSvcDiscRsp(resp->pDataList, resp->len); // save data to queue. } }break; case ATT_READ_BY_TYPE_RSP : { attReadByTypeRsp_t * resp = (attReadByTypeRsp_t *)&(gattMsg->msg.readByTypeRsp); Log_printf(LogModule_App1, Log_INFO, "response len: %d", resp->len); Log_printf(LogModule_App1, Log_INFO, "numPairs: %d", resp->numPairs); Log_printf(LogModule_App1, Log_INFO, "dataLen: %d", resp->dataLen); for(int i=0; i < resp->len; i++) { Log_printf(LogModule_App1, Log_INFO, "%d", resp->pDataList[i]); } }break; default: break; } }
I am receiving "ATT_READ_BY_TYPE_RSP" The parsing logic is present in the above code snippet.
I print the contents of "attReadByTypeRsp_t" structure and get a very value for the datalength field.
I have also printed the raw data contents of "attReadByTypeRsp_t" below, the below contents are results of a different handle search.
gattMsg->msg.readByTypeRsp.len = 7;
gattMsg->msg.readByTypeRsp.numPairs = 0x05;
gattMsg->msg.readByTypeRsp.pDataList = 0xC3, 0x43, 0x00, 0x20;
gattMsg->msg.readByTypeRsp.dataLen = 0xEB11; // Very large
0x05, 0x00, 0x07, 0x00, 0xC3, 0x43, 0x00, 0x20, 0x11, 0xEB
Hi,
This is definitely, strange by reading the attReadbyTypeRsp_t structure, you may not need this field.
For instance, here is how I parse it:
display_index += 1; attReadByTypeRsp_t *response = (attReadByTypeRsp_t *)&(gattMsg->msg.readByTypeRsp); MenuModule_printf(display_index, 0, "GATT status: Read by type %d", response->numPairs); for (int i = 0; i < response->numPairs; i++) { uint16_t attributeHandle = BUILD_UINT16(response->pDataList[i * response->len + 0], response->pDataList[i * response->len + 1]); uint16_t endHandle = BUILD_UINT16(response->pDataList[i * response->len + 2], response->pDataList[i * response->len + 3]); display_index += 1; MenuModule_printf(display_index, 0, "GATT status: Read by type: Handle: %x | %x", attributeHandle, endHandle); } break;
Can you try this and let me know the results?
Best,
Nima Behmanesh
Hi Sandeep,
I will need to contact R&D and reproduce the issue on my side as well. What SDK version are you using? I believe it was missing from your original post.
Best,
Nima Behmanesh
Hi Sandeep,
I'm still looking into this, and will get back to you no later than Friday.
Best,
Nima Behmanesh
Hi Sandeep,
Do the holidays, my responses will be a little bit delayed. Thank you for your patience in resolving this issue.
Best,
Nima Behmanesh
Hi Sandeep,
Do you mind testing on the latest SDK to see if the issue still persists?
Best,
Nima Behmanesh
Hi Nima,
The below image shows that the SDK is compatible for CC27 chipsets. I have a CC27 board with me and I have loaded the above code on to it as well. I see the same issue being replicated on the CC27 board as well. Could this really be an SDK issue?
Hi Sandeep,
Were you able to try the code snippet pasted above?
Best,
Nima Behmanesh
Hi Sandeep,
The way the information is parsed is specified by the Bluetooth Core Specification. If you need to handle the data in a different task, I'd suggest possibly formatting the information the way I have it above, and placing it in within a struct that can be shared between the tasks.
Best,
Nima Behmanesh
HI Nima,
You are absolutely right when you say "The way the information is parsed is specified by the Bluetooth Core Specification". Since the strcut has a pointer field (pDataList) and a datalen field, It was my understanding that the the datalen would tell how many bytes to read from the pDataList.
Also, given the code snippet that you have shared earlier, Is it right to assume that "response->numPairs * 4" captures the entire contents of pDataList?
Hi Sandeep,
I believe this is correct. Though I believe you can copy the code snippet directly, and this should capture all of the pairs of attribute handles.
Best,
Nima Behmanesh
Hi Nima,
On the peripheral I have 1 service and five characteristics as shown below.
I have taken the reference of the code snippet above and have extracted data from it. The numpairs is 5 and the length of each pair is 7.
The data is shown below.
0x02,0x00, 0x18,0x03, 0x00, 0x01,0xE0,
0x06,0x00, 0x18,0x07, 0x00, 0x02,0xE0,
0x0A,0x00, 0x18,0x0B, 0x00, 0x03,0xE0,
0x0E,0x00, 0x18,0x0F, 0x00, 0x04,0xE0,
0x12,0x00, 0x18,0x13, 0x00, 0x05,0xE0
The code snippet used to extract the above data :
From what I understand, The First 2 bytes are start handles, bytes- 3 and 4 are end handles. Since I know the UUID of my device I can confidently say that the last 2 bytes are UUIDs.
I see that the end handles are not in sync with start handles. Since the datalen field has an invalid value, could it be possible that the rest of the fields are also improper? is this data which I have received from the stack the correct one?
Hi Sandeep,
Do you mind reattaching the picture of the services? It isn't loading for me.
I see that the end handles are not in sync with start handles.
Do you mind elaborating what you mean by they are not in sync?
Best,
Nima Behmanesh
Hi Sandeep,
After looking into this and trying some things on my end, I see where the confusion is coming from, and so I feel the need to step back and start from scratch.
First, the code I had written before isn't totally correct. To understand why, we need to look at the spec.
1. Let's take a look at the ATT_READ_BY_TYPE_RSP
So, there are only two fields here that we care about, Length and the Attribute Data List. This maps to two fields in the attReadByTypeRsp_t struct that we are parsing through.
Length = attReadByTypeRsp_t.len
Attribute Data List = attReadByTypeRsp_t.pDataList
Moving forward, these are the only two fields we need from the struct. Ignore dataLen completely (to be honest, it shouldn't even be there).
Also note that we are getting attribute handle-value pairs. We aren't getting start handles and end handles. What we are getting is a handle to the attribute, and the value of that attribute. This is important, because now we must look at GATT.
2. Part G. Generic Attribute Profile Section 3.3.1
Here we see what that value portion of the attReadByTypeRsp_t actually looks like:
We are also doing little endian, so we will need to reverse the order of the pDataList that we are retrieving:
case ATT_READ_BY_TYPE_RSP: { attReadByTypeRsp_t att = (attReadByTypeRsp_t)gattMsg->msg.readByTypeRsp; MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0, "ATT_READ_BY_TYPE_RSP len: %d numPairs: %d", att.len, att.numPairs); display_index++; for (uint8_t i = 0; i < att.numPairs; i++) { /* This is the Attribute Handle */ uint16_t attHandle = BUILD_UINT16(att.pDataList[i * att.len + 0], att.pDataList[i * att.len + 1]); MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0,"ATT Handle: %x", attHandle); display_index++; /* This is the index to the beginning of the value data AFTER the attribute handle */ uint8_t index = i * att.len + 2; /* The characteristic value data */ uint8_t data1 = att.pDataList[index]; // Bit field of characteristic properties uint8_t data2 = att.pDataList[index + 1]; // Second Byte of Characteristic Value Handle uint8_t data3 = att.pDataList[index + 2]; // First Byte of Characteristic Value Handle /* If we were using 128-bit Bluetooth UUIDs, then we would have 16 of these instead of 2. */ uint8_t data4 = att.pDataList[index + 3]; // Second byte of UUID uint8_t data5 = att.pDataList[index + 4]; // First byte of UUID /* Since we are in little endian, we have to reverse the order to make the values make sense. */ MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0,"UUID: %x%x Val Handle: %x%x Properties: %x", data5, data4, data3, data2, data1); display_index++; } } break;
I tried this on the device info service (UUID 0x180A) and this was the output:
This makes sense, especially if we consider our ATT_MTU size of 27bytes (len is 7, we have 3 pairs, so 27bytes in total). The ATT_MTU size may be different in your application. I've also verified that the properties and UUIDs I expect are what I'm getting.
Lastly, I'll parse through the image you attached:
Attribute Handle: 0x0002, Properties: 0x18 (GATT_PROP_WRITE | GATT_PROP_NOTIFY), Value Handle: 0x0003, UUID: 0xE001
I hope that helps, and please let me know if you have any questions!
Best,
Nima Behmanesh
Hi Nima,
Thanks a lot for the detailed explanation about the packet type. It was very informative as well. I tested the above sequence in my code and I am able to make sense out of it now. With this, I should be able to close the client implementation.
Once again thanks a bunch,
Sandeep