This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

GATTServApp_RegisterService - attribute table vs callbacks

Other Parts Discussed in Thread: CC2540

The GATTServApp_RegisterService() registers a list of attribute descriptors and a list of callbacks.  When a remote device reads a characteristic value, GATT invokes the read callback and the read callback function returns the characteristic value (via pValue and pLen).  Similarly, when remote device writes a characteristic value, GATT invokes the write callback, passing the characteristic value to the write callback.  

So my question is, does the attribute array really need the pointer to the value since the value is handled in the read/write callbacks?  

For example, in the heartrate sample snippet below, is "&heartRateSensLoc" really needed or used by the GATT server code? or could one pass NULL pointer instead?

// Sensor Location Declaration
{
{ ATT_BT_UUID_SIZE, characterUUID },
GATT_PERMIT_READ,
0,
&heartRateSensLocProps
},

// Sensor Location Value
{
{ ATT_BT_UUID_SIZE, heartRateSensLocUUID },
GATT_PERMIT_READ,
0,
&heartRateSensLoc
},

  • In my own attribute table, I tried setting pointers to characteristic values to NULL and everything still seems to work correctly, suggesting that the pValue element in gattAttribute_t struct is not needed for characteristic value attributes.  Confirmation from TI would be appreciated since consequence of NULL pointers may reveal itself at the worst possible time :)

    TIA,

    Richard

  • It has come to my attention in the field that I have a customer who is also looking for an answer to this question.

    Thanks,

    Stuart

  • You have to put the UUID in the Attribute table or else the GAP won't know what callback to call.  You also have to put the declaration. You should put the right pValue, but you don't have to

    In the callback, setting pValue to the pointer of you characteristic is kind of a hack.  One of the arguements of the callbacks is a gattAttribute_t struct called pAttr. This struct has a pointer (pValue) that is set by what you put in the attribute table. This is the value I prefer to give to pValue. It feels cleaner.

    If you want to use the stack properly, you should give the right pointer to the attribute table, but you don't HAVE to do anything because most any code can be hacked to work in a round about way. I'm not aware of any other consequence of giving the attribute table the wrong pointer. You may be in a bad spot if a future version of the stack comes out that requires you to be stricter with coding.

  • Hi Stuart,

    The attribute value field in the GATT table should be initialized with a pVariable as per the specs. The pValue in the callbacks should be equal to the pVariable.

    Also the same variable is accessed in the HeartRate_GetParameter and HeartRate_SetParameter functions.   

    So we do not recommend the NULL pointers in the GATT table even though it may work for some cases.

  • Hi Zahid,

    Could you please clarify how the Gatt Server uses these variable pointers, if at all?

    The call to GATTServApp_RegisterService() specifies callbacks, gattServiceCBs_t, to handle characteristic reads and writes; are there circumstances when the Gatt Server accesses variables directly via attribute table rather than calling the read/write callbacks?

    Or perhaps, the variable pointers (gattAttribute_t pValue) are only used by profiles above the gatt server, not by the gatt server itself? The distinction is relevant to applications using the gatt server directly.

    Richard

  • Hi Richard,

    The GATTServApp_RegisterService() also registers the GATT attribute table/list. The table is passed to the GATT server as a pointer (gattAttribute_t *pAttrs). There is only one copy of the table. The GATT server just uses pointers to point to the same table so in essence it is accessing the table directly using pointers. Hope this makes it a bit more clear.

  • Hi Zahid,

    I understand that the GATT Server retains a pointer to the attribute table and understand that table is the source of information for the GATT server to publish characteristics, attributes, handles, properties, etc. The attribute table contains Service and Characteristic definitions. Characteristic definitions consist of at least 2 attributes, a characteristic declaration and a Characteristic Value declaration. The Characteristic Value declaration's pValue is subject of my question; namely, what does the GATT server do with this pointer, if anything?

    When the GATT server receives a request to read an attribute value, it seems the GATT server has 2 choices:
    1. It can call the registered read callback, gattServiceCBs_t pfnReadAttrCB
    OR
    2. It can read the value via the attribute value pointer, pValue.

    Likewise, when the GATT server receives a request to write an attribute value, it has 2 choices:
    1. It can call the registered write callback, pfnWriteAttrCB
    OR
    2. It can write the value via the attribute's value pointer, pValue.

    In our case, all characteristic value descriptors have pValue set to NULL. Our CC2540 peripheral application is interoperating correctly with PC, Android and IOS applications; the read and write callbacks are being invoked as expected.

    Now you are recommending that the pValue pointers not be NULL, so I would like to understand what the GATT server will do with those value pointers if I make them non-NULL?

    Richard

  • Hi Richard,

    I think you answered your question already, the GATT server uses the pValue to read and write to it.

    For example in heartRate_WriteAttrCB:

    *(pAttr->pValue) = pValue[0];

    in heartRate_ReadAttrCB:

    pValue[0] = *pAttr->pValue;

     

    Are you not using *pAttr->pValue to read and write in the callbacks? Otherwise the non-NULL pointer for pValue is just used in the application layer, for example to set heartrate measurements.

  • Hi Zahid,

    The heartRate_WriteAttrCB is not the GATT server, it is profile code that resides above the GATT server.  My question is about the GATT server for which we have no source code.

    I'm beginning to guess that the GATT server does not use the pValue pointer at all; that pValue is intended to be used by the profile layer.  (This would be so much simpler if TI were to share more source code, sigh)

    Richard