How do you define Gatt descriptors using GattCharacteristic attributes (GattAttribute class)

Here is the reference to Gatt Descriptors: Assigned Numbers | Bluetooth® Technology Website

I wish to incorporate some of these in my defined characteristic.

I am looking at the GattServer example and the GattCharacteristic.h file for guidance, but here is just sets descriptors to NULL.

GattCharacteristic(
    const UUID &uuid,
    uint8_t *valuePtr = NULL,
    uint16_t len = 0,
    uint16_t maxLen = 0,
    uint8_t props = BLE_GATT_CHAR_PROPERTIES_NONE,
    GattAttribute *descriptors[] = NULL,
    unsigned numDescriptors = 0,
    bool hasVariableLen = true
) : _valueAttribute(uuid, valuePtr, len, maxLen, hasVariableLen),
    _properties(props),
    _descriptors(descriptors),
    _descriptorCount(numDescriptors),
    readAuthorizationCallback(),
    writeAuthorizationCallback(),
    _update_security(SecurityRequirement_t::NONE) {
    _valueAttribute.allowWrite(isWritable(_properties));
    _valueAttribute.allowRead(isReadable(_properties));

I then could not make sense of the class “GattAttribute” and the section on how to construct an attribute.

By way of an example, I am trying to use 0x2901, which allows you to create a Characteristic User Description.

Any guidance greatly appreciated.

Thanks

Colin.

I know I’m making a basic error here, but I cannot see it.

Walking through an example…

If I use the bleButton as my example.

I can see that within ButtonService.h we construct our service:

ButtonService(BLE &_ble, bool buttonPressedInitial) :
    ble(_ble), buttonState(BUTTON_STATE_CHARACTERISTIC_UUID, &buttonPressedInitial, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)
{
    GattCharacteristic *charTable[] = {&buttonState};
    GattService         buttonService(ButtonService::BUTTON_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
    ble.gattServer().addService(buttonService);
}

Then my understanding is that our characteristic is defined by buttonState which is handled by our template ReadOnlyGattCharacteristic<bool> buttonState;

Then from this template we can construct our characteristic, which is made up of:
a UUID, which is BUTTON_STATE_CHARACTERISTIC_UUID
an initial value which is &buttonPressedInitial
and some additional properties: GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY

I can see that the template also allows me to add in two additional parameters which have default values assigned:

GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0

But this is where I am stuck.

Going to GattAttribute.h I am given an example:

@code

 * // declare a value of 2 bytes within a 10 bytes buffer

 * const uint8_t attribute_value[10] = { 10, 50 };

 * GattAttribute attr = GattAttribute(

 *    0x2A19, // attribute type

 *    attribute_value,

 *    2, // length of the current value

 *    sizeof(attribute_value), // length of the buffer containing the value

 *    true // variable length

 * );

 * @endcode

But when I add this to my characteristic as follows:

    uint8_t attribute_value[10] = { 10, 50 };       // define my attribute value

    ButtonService(BLE &_ble, bool buttonPressedInitial) :
    ble(_ble), 
    buttonState(BUTTON_STATE_CHARACTERISTIC_UUID, 
                    &buttonPressedInitial,
                    GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY,
                    GattAttribute( 0x2A19, attribute_value, 2, sizeof(attribute_value), true),
                    1 )
{
    GattCharacteristic *charTable[] = {&buttonState};
    GattService         buttonService(ButtonService::BUTTON_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
    ble.gattServer().addService(buttonService);
}

I get an error:

No matching constructor for initialization of ‘ReadOnlyGattCharacteristicstd::uint8_t’ (aka ‘ReadOnlyGattCharacteristic’)
mbed-os/features/FEATURE_BLE/ble/GattCharacteristic.h:1832:5:
note: candidate constructor not viable: no known conversion from ‘GattAttribute’ to ‘GattAttribute **’ for 4th argument
mbed-os/features/FEATURE_BLE/ble/GattCharacteristic.h:1812:7:
note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 5 were provided

I think I’ve just earned my PhD in solving this.

So, within ButtonService class we add:

private:
BLE &ble;
GattAttribute *ButtonState_attr;
ReadOnlyGattCharacteristic buttonState;
};

Then when constructing our ButtonService we add in

ButtonService(BLE &_ble, bool buttonPressedInitial) :
    ble(_ble), 
    buttonState(BUTTON_STATE_CHARACTERISTIC_UUID, 
         &buttonPressedInitial, 
         GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY,
         &ButtonState_attr, 1)
{

    ButtonState_attr = new GattAttribute( ----- ADD IN DESCRIPTOR ATTRIBUTES---);

    GattCharacteristic *charTable[] = {&buttonState};
    GattService         buttonService(ButtonService::BUTTON_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
    ble.gattServer().addService(buttonService);
}

Best feeling… when you see proof that it’s working (made a few other mods too…)

1 Like

Hey we meet again! I was trying to do the same :sweat_smile: Thanks now.

Could you please show how you added the descriptor attribute parameters such as the string “Button State”?

It’s a small world…

As shown above we have:

ButtonState_attr = new GattAttribute( ----- ADD IN DESCRIPTOR ATTRIBUTES—);

To set those up we simply:

// Define our user description uuid
const static uint16_t DIGITAL_USERDESCRIPTION_UUID  = 0x2901;
// Then we create our text string
uint8_t BUTTONSTATE_USRDESCR[13] = "Button State";
// Now we insert into our new GattAttribute
ButtonState_attr = new GattAttribute( DIGITAL_USERDESCRIPTION_UUID, // attribute type
            BUTTONSTATE_USRDESCR, sizeof(BUTTONSTATE_USRDESCR), 20, // length of the buffer containing the value
            true // variable length
        );

And that’s it.

I tried something similar and the code compiles. But then flashed to my nRF52832, it results in a hard fault exception, throwing me the following message to the serial monitor.

++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0x1E752
Error Value: 0x20007AF0
Current Thread: application_unnamed_thread Id: 0x200040B4 Entry: 0x1D4BD StackSize: 0x1000 StackMem: 0x20009158 SP: 0x20009F48 
For more info, visit: https://mbed.com/s/error?error=0x80FF013D&tgt=NRF52_DK
-- MbedOS Error Info --
Hello World 0
Na:0.062842757,K:0.108766310,Cl:0.034644082,pH:0.238530546

++ MbedOS Fault Handler ++

FaultType: HardFault

Context:
R0: E25A2EA5
R1: 20009F50
R2: 0
R3: 200044EC
R4: 0
R5: 0
R6: 2000A08C
R7: E25A2EA5
R8: 20009FB4
R9: 4
R10: 5
R11: 20009F50
R12: 55DB1
SP   : 20009F48
LR   : 12B15
PC   : 1E752
xPSR : 61000000
PSP  : 20009F28
MSP  : 2000FFD0
CPUID: 410FC241
HFSR : 40000000
MMFSR: 0
BFSR : 82
UFSR : 0
DFSR : 0
AFSR : 0
BFAR : E25A2EA5
Mode : Thread
Priv : Privileged
Stack: PSP

-- MbedOS Fault Handler --

I was doing an out of bounds access to an array I created to hold the descriptors. It has been fixed and it’s working now. Thanks :slight_smile:

1 Like