Puzzled by Server handling of write events in examples.

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

I've been studying the API documentation and the 100 projects as well as trying some experiments with my own custom service. I'm puzzled by the typical code for handling write events when a custom characteristic supports both read and write. Typically in the 100 projects it is something like:

   

case CYBLE_EVT_GATTS_WRITE_REQ:
case CYBLE_EVT_GATTS_WRITE_CMD_REQ:
  wrReqParam = (CYBLE_GATTS_WRITE_REQ_PARAM_T *) eventParam;
  if(wrReqParam->handleValPair.attrHandle == MY_HANDLE)
  {
     CYBLE_GATT_HANDLE_VALUE_PAIR_T hvp;
     uint8 theValue[2];
     theValue[0] = wrReqParam->handleValPair.value.val[0];
     theValue[1] = wrReqParam->handleValPair.value.val[1];

     hvp.attrHandle = MY_HANDLE;
     hvp.value.val = theValue;
     hvp.value.len = 2;
     /* Report data to BLE component for sending data when read by Central device */
     CyBle_GattsWriteAttributeValue(&hvp, 0, &cyBle_connHandle, CYBLE_GATT_DB_LOCALLY_INITIATED);
  }

   

Three things puzzle me about this:

   
        
  1. Why is it necessary for application code to write the received value to the database? The API description (and common sense) implies that the stack should do this automatically subject to permission settings.
  2.     
  3. Why is it necessary to copy the handleValPair? Why not just specify '&(wrReqParam->handleValPair)' as the first parameter to ..WriteAttributeValue?
  4.     
  5. Why is the last parameter to ..WriteAttributeValue ..LOCALLY_INITIATED rather than ..PEER_INITIATED when we are responding to a peer write? As far as I can gather from the documentation this will bypass server permission settings.
  6.    
   

Anyone have any insight into this as it is really baffling me!

0 Likes
1 Solution
Anonymous
Not applicable

John,

   

Please find my comments inline:

   

1. Why is it necessary for application code to write the received value to the database? The API description (and common sense) implies that the stack should do this automatically subject to permission settings.

   

[ROIT]: The API to update the received value to database has been exposed to Application layer so that the server can choose which data to update to database. It does makes sense to update the database with value written to a characteristic directly, but considering scenario where the data can also be locally update, it is a better option to open this directly to users. 

   

2. Why is it necessary to copy the handleValPair? Why not just specify '&(wrReqParam->handleValPair)' as the first parameter to ..WriteAttributeValue?

   

[ROIT]: This is an example code snippet, which may have been written to explain how the handle value pair can be updated and then used by API to update database. You can very well use the 'wrReqParam->handleValPair' directly.

   

3. Why is the last parameter to ..WriteAttributeValue ..LOCALLY_INITIATED rather than ..PEER_INITIATED when we are responding to a peer write? As far as I can gather from the documentation this will bypass server permission settings.

   

[ROIT]: Agreed. Can you point out the projects where you saw LOCALLY_INITIATED used rather than PEER_INITIATED?

View solution in original post

0 Likes
4 Replies
Anonymous
Not applicable

John,

   

Please find my comments inline:

   

1. Why is it necessary for application code to write the received value to the database? The API description (and common sense) implies that the stack should do this automatically subject to permission settings.

   

[ROIT]: The API to update the received value to database has been exposed to Application layer so that the server can choose which data to update to database. It does makes sense to update the database with value written to a characteristic directly, but considering scenario where the data can also be locally update, it is a better option to open this directly to users. 

   

2. Why is it necessary to copy the handleValPair? Why not just specify '&(wrReqParam->handleValPair)' as the first parameter to ..WriteAttributeValue?

   

[ROIT]: This is an example code snippet, which may have been written to explain how the handle value pair can be updated and then used by API to update database. You can very well use the 'wrReqParam->handleValPair' directly.

   

3. Why is the last parameter to ..WriteAttributeValue ..LOCALLY_INITIATED rather than ..PEER_INITIATED when we are responding to a peer write? As far as I can gather from the documentation this will bypass server permission settings.

   

[ROIT]: Agreed. Can you point out the projects where you saw LOCALLY_INITIATED used rather than PEER_INITIATED?

0 Likes
Anonymous
Not applicable

Thanks @ROIT - that was very useful.

   

Re point 3, the extract in my original post was lightly adapted from:

   

https://github.com/cypresssemiconductorco/PSoC-4-BLE/blob/master/100_Projects_in_100_Days/Day048_SPI...

   

However, I have seen this many other places including, for example, AN91162.

   

As another related point, I think many of the examples are not careful enough about returning the right response. If a write is rejected or modified (for example saturating a numeric value), then the client should be informed so it can read back the actual value.

0 Likes
Anonymous
Not applicable

John,

   

Thanks for pointing out the example project (and AN). We will update it with correct method of database update and try to release it as soon as possible.

   

As for responses to be sent against write requests and commands, the reason error codes where not introduced was to prevent complexity in the projects and make it easy for users to understand the basics of BLE events. I do agree that they should be handled correctly and we have introduced error response in few of these projects (please refer the BLE mesh project at https://github.com/cypresssemiconductorco/PSoC-4-BLE/tree/master/100_Projects_in_100_Days/Day049_BLE... ). 

   

Hope this helps.

Anonymous
Not applicable

One other point of detail if you are reviewing these documents:

   

Parameter 2 to CyBle_GattsWriteAttributeValue is documented as a UINT16 "offset" but the macro "FALSE" is passed in AN91162, which is correct but misleading.

0 Likes