Summary

In the previous article I showed you how to create a BLE Central that could attach to a BLE peripheral that is advertising a custom service.  Then, I showed you how to write values to the LED Characteristic in the Peripheral GATT Server.  In this article Ill show you how to set the CCCD and what happens when the Peripheral notifies.

The steps to build this project will be as follows

  1. Create a new project with copy/paste
  2. Write the CCCD
  3. Handle the new GATT Events

Create a new project by copy/paste

I wanted to have three different projects for each of the steps in this series of articles.  To create the 2nd example (the subject of this article) Ill just do a copy/paste and then fix a few things.  Start with the copy.

When you paste it will ask you to give a new name to the directory.

Give the main file a new name, in this case ex02CCCD.c

And create a new make target.

Fix the makefile with the new name of the source file.

Build and test to make sure that everything still works…. and it seems to.

Write the CCCD

The Peripheral that we are talking to in this example has a CapSense Characteristic that has a Client Characteristic Configuration Descriptors, also known as the CCCD.   When you set the CCCD to 1, the Peripheral will then send you notifications anytime the underlying Characteristic changes.  WICED has some utility functions to help you interact with the remote GATT server.  To add them to your project, first include the header file.

#include "wiced_bt_gatt_util.h"

Then modify your makefile to include the library.

$(NAME)_COMPONENTS += gatt_utils_lib.a

To actually turn on/off the CCCD you simply call the library function wiced_bt_util_set_gatt_client_config_descriptor.  Ill add a case ‘n’ to turn on notifications and a case ‘N’ to turn them off.  Notice the 0x12 is hardcoded in two places, something which is really bad and Ill fix in the next article.  Don’t forget to add the two cases to the help message.

     case 'n':
         WICED_BT_TRACE("CCCD On\n");
         if(conn_id )
             wiced_bt_util_set_gatt_client_config_descriptor(conn_id,0x12,1); // Very bad hardcode 0x12

         break;

     case 'N':
         WICED_BT_TRACE("CCCD Off\n");
         if(conn_id )
             wiced_bt_util_set_gatt_client_config_descriptor(conn_id,0x12,0); // Very bad hardcode 0x12
         break;


    case '?':
        /* Print help */
        WICED_BT_TRACE( "\n" );
        WICED_BT_TRACE( "+------- Available Commands -------+\n" );
        WICED_BT_TRACE( "|  n    CCCD On                    |\n" );
        WICED_BT_TRACE( "|  N    CCCD Off                   |\n" );

Now when I test… I can press the ‘n’ to set the CCCD.  When I touch the CapSense slider I seem to get a whole bunch of “Unknown GATT Event 1″s (we will figure that out in just a bit).  So it seems to be working.  When I press ‘N’ I don’t get the messages.


Is there something special about the function wiced_bt_util_set_gatt_client_config_descriptor?  Nope.  If you right click on it, you can look at the source code.  This code looks exactly like the “writeLed” function that we wrote in the previous example.  The only difference is that instead of allocating a buffer using wiced_bt_get_buffer the author of this function allocated the buffer on the stack.

/*
 * Format and send GATT Write Request to set value of a G
 */
wiced_bt_gatt_status_t wiced_bt_util_set_gatt_client_config_descriptor(uint16_t conn_id, uint16_t handle, uint16_t value)
{
    wiced_bt_gatt_status_t status;
    uint8_t                buf[sizeof(wiced_bt_gatt_value_t) + 1];
    wiced_bt_gatt_value_t *p_write = ( wiced_bt_gatt_value_t* )buf;
    uint16_t               u16 = value;

    // Allocating a buffer to send the write request
    memset(buf, 0, sizeof(buf));

    p_write->handle   = handle;
    p_write->offset   = 0;
    p_write->len      = 2;
    p_write->auth_req = GATT_AUTH_REQ_NONE;
    p_write->value[0] = u16 & 0xff;
    p_write->value[1] = (u16 >> 8) & 0xff;

    // Register with the server to receive notification
    status = wiced_bt_gatt_send_write (conn_id, GATT_WRITE, p_write);
    return status;
}

Handle the new GATT Events

In the screenshot of the serial terminal above you can see a bunch of “Unknown GATT Event 1”.  What is that?  To figure that out, right click on the GATT_CONNECTION_EVT and go to declaration.

This will take you to this enumeration, which shows all of the possible GATT events.  And, in this table you can see that 0x01 is GATT_OPERATION_CPLT_EVT.

/** GATT events */
typedef enum
{
    GATT_CONNECTION_STATUS_EVT,                         /**< GATT connection status change. Event data: #wiced_bt_gatt_connection_status_t */
    GATT_OPERATION_CPLT_EVT,                            /**< GATT operation complete. Event data: #wiced_bt_gatt_event_data_t */
    GATT_DISCOVERY_RESULT_EVT,                          /**< GATT attribute discovery result. Event data: #wiced_bt_gatt_discovery_result_t */
    GATT_DISCOVERY_CPLT_EVT,                            /**< GATT attribute discovery complete. Event data: #wiced_bt_gatt_event_data_t */
    GATT_ATTRIBUTE_REQUEST_EVT,                         /**< GATT attribute request (from remote client). Event data: #wiced_bt_gatt_attribute_request_t */
    GATT_CONGESTION_EVT                                 /**< GATT congestion (running low in tx buffers). Event data: #wiced_bt_gatt_congestion_event_t */
} wiced_bt_gatt_evt_t;

So, lets update the GATT Event handler for that case.  What Ill do is just printout the information that is sent (which is of type wiced_bt_gatt_event_data_t).

    case GATT_OPERATION_CPLT_EVT:

        // When you get something back from the peripheral... print it out.. and all of its data

        WICED_BT_TRACE("Gatt Event Complete Conn=%d Op=%d status=0x%X Handle=0x%X len=%d Data=",
                p_data->operation_complete.conn_id,
                p_data->operation_complete.op,
                p_data->operation_complete.status,
                p_data->operation_complete.response_data.handle,
                p_data->operation_complete.response_data.att_value.len);

        for(int i=0;i<p_data->operation_complete.response_data.att_value.len;i++)
        {
            WICED_BT_TRACE("%02X ",p_data->operation_complete.response_data.att_value.p_data[i]);
        }
        WICED_BT_TRACE("\n");

        break;

After I program the CYW920719Q40EVB_01 you can see that things seem to be working.  Specifically, I found the peripheral, connected to it, set the CCCD for CapSense, then pressed the CapSense slider on the Peripheral.  Notice that after I set the CCCD, I get an event complete with op=3 and handle=0x12.  This is the write response message for the CCCD handle. (remember the hardcoded 0x12 from above).

The other thing to see is that each time there is CapSense update, the Peripheral sends out a notification of handle 0x11 with the current CapSense slider value.  Notice that the slider value is little endian.  You can see the last value is 0xFFFF which is a no touch in CapSense.

The “op” is just one of the enumerated values from the list below.  You can see the 0x06 is Notification.  And 0x03 is Write.

/** GATT client operation type, used in client callback function
*/
enum wiced_bt_gatt_optype_e
{
    GATTC_OPTYPE_NONE             = 0,    /**< None      */
    GATTC_OPTYPE_DISCOVERY        = 1,    /**< Discovery */
    GATTC_OPTYPE_READ             = 2,    /**< Read      */
    GATTC_OPTYPE_WRITE            = 3,    /**< Write     */
    GATTC_OPTYPE_EXE_WRITE        = 4,    /**< Execute Write */
    GATTC_OPTYPE_CONFIG           = 5,    /**< Configure */
    GATTC_OPTYPE_NOTIFICATION     = 6,    /**< Notification */
    GATTC_OPTYPE_INDICATION       = 7     /**< Indication */
};

You can find all of the source code for these projects at github.com/iotexpert/PSoc4BLE-Central 

Recommended Posts

No comment yet, add your voice below!


Add a Comment

Your email address will not be published. Required fields are marked *