How to create a Custom Profile-Server

Document created by Iliana Berenice Tejeda Hernandez Employee on Sep 9, 2015
Version 1Show Document
  • View in full screen mode

For this example, the BLE stack VERSION was configure to create a Custom Profile with the KW40Z.

The Custom to create is the Humidity Sensor and is based on the Temperature Sensor.

The First thing to know is that the Generic Attribute Profile (GATT) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules.


GATT defines two roles: Server and Client.

  • The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client.
  • The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations.



   Figure 1. GATT Client-Server


      GATT Database establishes a hierarchy to organize attributes. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors are defined attributes that describe a characteristic value.

To define a GATT Database several macros are provided by the GATT_DB API.




Figure 2. GATT database


     To know if the Profile or service is already defined on the specification, you have to look for on Bluetooth SIG profiles and check on the ble_sig_define module if is already declared on the code. In our case the Service is not declared(because is a Custom Profile) but the characteristic of the humidity it is on the specification but not on ble_sig_define.


/*! Humidity Charactristic UUID */
#define gBleSig_Humidity_d                      0x2A6F


The Humidity Sensor is going to have the GATT Server, because is going to be the device that has all the information for the GATT Client.

The Application works like the Temperature Sensor, every time that you press the SW1 on USB is going to send the value.

On the Temperature Sensor demo have the Battery Service and Device Information, so you only have to change the Temperature Service to Humidity Service.



Figure 3. GATT database of Humidity Sensor




     First thing to do is define the Humidity Server that has 16 bytes.

To define a new Server or a Characteristic is in gatt_uuid128.h which is located in the application folder.

All macros, function or structure in SDK have a common template which helps the application to act accordingly.

/* Humidity */ 
UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)


All the Service and Characteristics is declared in gattdb.h. Descriptors are declared after the Characteristic Value declaration but before the next Characteristic declaration. In this case the permission is the CharPresFormatDescriptor that have specific description by the standard. The Units of the Humidity Characteristic is on Percentage that is 0x27AD.

Client Characteristic Configuration Descriptor(CCCD) is a descriptor where clients write some of the bits to activate Server notifications and/or indications


PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity)
CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c))
 VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25)
DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00)

     After that, create a folder humidity in the next path C:\....\KW40Z_BLE_Software_1.1.2\ConnSw\bluetooth\profiles. Found the temperature folder, copy the temperature_service and paste inside of the humidity folder with another name (humidity_service)

Then go back and look for the interface folder, copy temperature_interface and change the name (humidity_interface) in the same path.


     On the humidity_interface file should have the following code.

The Service structure has the service handle, and the initialization value.

/*! Humidity Service - Configuration */
typedef struct humsConfig_tag
    uint16_t serviceHandle;
    int16_t initialHumidity;        
} humsConfig_t;


The next configuration structure is for the Client; in this case we don’t need it.

/*! Humidity Client - Configuration */
typedef struct humcConfig_tag
    uint16_t    hService;
    uint16_t    hHumidity;
    uint16_t    hHumCccd; 
    uint16_t    hHumDesc; 
    gattDbCharPresFormat_t  humFormat;
} humcConfig_t;


     At minimum on humidity_service file, should have the following code.

The service stores the device identification for the connected client. This value is changed on subscription and non-subscription events.

/*! Humidity Service - Subscribed Client*/
static deviceId_t mHums_SubscribedClientId;


     The initialization of the service is made by calling the start procedure. This function is usually called when the application is initialized. In this case is on the BleApp_Config(). On stop function, the unsubscribe function is called.


bleResult_t Hums_Start (humsConfig_t *pServiceConfig)
    mHums_SubscribedClientId = gInvalidDeviceId_c;
    return Hums_RecordHumidityMeasurement (pServiceConfig->serviceHandle, 

bleResult_t Hums_Stop (humsConfig_t *pServiceConfig)
    return Hums_Unsubscribe();


     Depending on the complexity of the service, the API will implement additional functions. For the Humidity Sensor only have a one characteristic.

The measurement will be saving on the GATT database and send the notification to the client. This function will need the service handle and the new value as input parameters.

bleResult_t Hums_RecordHumidityMeasurement (uint16_t serviceHandle, int16_t humidity)
    uint16_t handle;
    bleResult_t result;
    bleUuid_t uuid = Uuid16(gBleSig_Humidity_d); 
    /* Get handle of Humidity characteristic */
    result = GattDb_FindCharValueHandleInService(serviceHandle,
        gBleUuidType16_c, &uuid, &handle);

    if (result != gBleSuccess_c)
        return result;

    /* Update characteristic value */
    result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t*)&humidity);

    if (result != gBleSuccess_c)
        return result;


    return gBleSuccess_c;


     After save the measurement on the GATT database with GattDb_WriteAttribute function we send the notification.

To send the notification, first have to get the CCCD and after check if the notification is active, if is active send the notification.

static void Hts_SendHumidityMeasurementNotification
  uint16_t handle
    uint16_t hCccd;
    bool_t isNotificationActive;

    /* Get handle of CCCD */
    if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd) != gBleSuccess_c)

    if (gBleSuccess_c == Gap_CheckNotificationStatus
        (mHums_SubscribedClientId, hCccd, &isNotificationActive) &&
        TRUE == isNotificationActive)
          GattServer_SendNotification(mHums_SubscribedClientId, handle);


     Steps to include the files into the demo.


1. Create a clone of the Temperature_Sensor with the name of Humidity_Sensor

2. Unzip the Humidity_Sensor folder.

3. In the fallowing path <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profiles\interface save the humidity_interface file.

4. In the <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profiles save the humidity folder

5. In the next directory <kw40zConnSoft_intall_dir>\ConnSw\examples\bluetooth\humidity_sensor\common replaces with the common folder.



      Steps to include the paths into the demo using IAR Embedded Workbench


Once you already save the folders in the corresponding path you must to indicate in the demo where are they.

1. Drag the files into the corresponding folder. The principal menu is going to see like this.

Figure 4. Principal Menu

2. Then click Option

Figure 5. Option


3. Click on the C/C++ Compiler and then on the Preprocessor

    Figure 6. Preposcessor Window


4. After that click on  "..." button to edit the include directories and then click to add a new path.

     Add the <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profile\humidity path.


Figure 7. Add a path



Finally compile and enjoy the demo!

NOTE: If you want to probe the demo using another board you must to run the humidity_collector demo too.

Figure 8. Example of the Humidity Sensor using the Humidity Collector demo.

1 person found this helpful