Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

 

           Transmitting BLE notifications is a straightforward process using the WICED APIs. The APIs are much more user friendly, however, with a conceptual understanding of the process. Before proceeding you should be comfortable with common terms in BLE as well as the very basics of the protocol. How do devices find one another? Which is the master and which is the slave? And which one advertises?

 

The question we’ll delve into today is: how do BLE devices exchange data? There is one key concept that must be understood to be able to instantiate BLE communication in your code: the GATT Database is the medium for tranceiving all data.

 

                In BLE, both the master (likely your phone) and the slave (likely your WICED device) are allowed to read or write to/from your GATT database. These reads and writes can follow any logical sequence of events:  the client can read data which is being continuously written by the slave, the client can write to the slave in order to tell the slave to write data to the GATT (the client will then perform a read), etc. These sequences are not fixed, and can be instantiated in any logical manner.

 

Additionally, the slave can send unrequested, unacknowledged “notifications” to the master, the master has the power to either ignore or listen to these notifications. This cuts out the complexities of reads and writes. The majority of BLE transmissions carried out are notifications. They are easy to use and very practical. For that reason, this post will demonstrate the execution of a BLE notification.

 

To send a notification, you must do two things: load the data into your GATT database and call the “notify” API to carry out the transmission at a hardware level.

 

The GATT database is not conceptual as it may have sounded up to this point—it’s to be clearly defined in every BLE app you ever create. The GATT database a hierarchy of services, characteristics, and descriptors. Some of these are mandatory—they will be identical in every app. The unique services and characteristics that you’ll be adding to your future apps are “vendor-specific.”

 

Within the GATT database there are services. Within services there are characteristics. Within characteristics there are descriptors. That’s all you need to know about the hierarchy within the GATT database. Characteristics are where the data is held, and where you’ll be writing in order to send data over BLE.

 

A service may have one or more characteristics. But a characteristic cannot exist outside of a service. For instance, although measuring someone’s heart rate only has one possible characteristic it requires a Heart Rate Service, and underneath it a Heart Rate Characteristic (the actual pulse rate). On the other hand, other services will require many characteristics which can all hold their own values. For example, a Vital Signs Service would have individual characteristics for pulse rate, blood pressure, respiratory rate, etc. For now, we will not discuss descriptors. They are only utilized for reads and writes to the GATT database (not notifications).

 

 

--------------------------------------------------------STEP-BY-STEP GUIDE TO FIRMWARE------------------------------------------------------

 

 

There are 5 distinct steps required to instantiate BLE notifications using the WICED API:

 

  1. Setup your GATT database
  2. Read the current value of your vendor-specific characteristic.
  3. Change that value.
  4. Write it back to your vendor-specific characteristic.
  5. Send the notification.

 

1.  Setting up the GATT database is the most difficult part of the process. The complexity of setting up your GATT database is dependent upon the complexity of your app. Contained in the sample firmware is likely the most simplified GATT database you will come across—aside from the mandatory inclusions, there is one service and one characteristic.

 

Each service must have a handle and a UUID. Each characteristic must have a handle and a handle value. These are unique values that must be defined by you. UUIDs can be generated randomly using an online generator.

 

In addition to these identifiers, each GATT definition must have defined permissions, property definitions, and lengths (number of bytes). The parameters used in the sample code are all you will need in order to send notifications. But there is a long list of these parameters available in How to Write WICED Smart Applications that guide you through the process of customizing your GATT database form the ground up. For further reading, I highly recommend reading about the GATT database parameters that are at your disposal in this document. 

 

                      const UINT8 ble_tx_gatt_database[]={

              /////////////////////mandatory for all apps//////////////////////////

              PRIMARY_SERVICE_UUID16 (0x0001, UUID_SERVICE_GATT),

 

 

              PRIMARY_SERVICE_UUID16 (0x0014, UUID_SERVICE_GAP),

 

 

              CHARACTERISTIC_UUID16 (0x0015, 0x0016, UUID_CHARACTERISTIC_DEVICE_NAME,

                                    LEGATTDB_CHAR_PROP_READ,

                                    LEGATTDB_PERM_READABLE, 16),

                'B','L','E',' ','D','a','t','a',' ','T','x',0x00,0x00,0x00,0x00,0x00,

 

 

              CHARACTERISTIC_UUID16 (0x0017, 0x0018, UUID_CHARACTERISTIC_APPEARANCE,

                                    LEGATTDB_CHAR_PROP_READ,

                                    LEGATTDB_PERM_READABLE, 2),

                BIT16_TO_8(APPEARANCE_GENERIC_TAG),

              /////////////////////////////////////////////////////////////////////

 

              ////////////////vendor specific, optional, customize///////////////

              PRIMARY_SERVICE_UUID128 (HANDLE_BLE_TX_SERVICE_UUID,

                                      UUID_BLE_TX_SERVICE),

 

              CHARACTERISTIC_UUID128 (0x0029, HANDLE_BLE_TX_VALUE_NOTIFY,

                                      UUID_BLE_TX_CHARACTERISTIC_NOTIFY,

                                      LEGATTDB_CHAR_PROP_NOTIFY,

                                      LEGATTDB_PERM_NONE, 1),

                '1','2','3','4','5','6','7',

              ////////////////////////////////////////////////////////////////////

          };

 

2.  Reading the current value of the characteristic you wish to write to is as simple as calling an API. First, we must instantiate a variable of type BLEPROFILE_DB_PDU, then call on the appropriate API to read. This API requires two parameters: the handle of the value you wish to read, and a pointer to the newly created variable.

 

                        BLEPROFILE_DB_PDU db_pdu;

            bleprofile_ReadHandle(HANDLE_BLE_TX_VALUE_NOTIFY, &db_pdu);

 

3.  In order to change the transmitted value, we change the "pdu" component of the db_pdu struct (.pdu[]) equal to the data we wish to send. In this case a constant:

 

            db_pdu.pdu[0] = my_data;

 

4.  Again, all we must do is call an API to write the changed value back to the characteristic, using the same parameters as the read:

 

            bleprofile_WriteHandle(HANDLE_BLE_TX_VALUE_NOTIFY, &db_pdu);

 

5. Lastly, we call the notify API to carry out the transmission at the hardware level. Note the parameters and emulate in your own code.

 

            bleprofile_sendNotification(HANDLE_BLE_TX_VALUE_NOTIFY,

                                      (UINT8 *)db_pdu.pdu, db_pdu.len);

 

                For the most basic BLE notification, there are no further steps that you need to take. In the sample app, we load the notification with an arbitrary constant and send it to out. But this very byte can be loaded with any data of our choosing: sensor data, status, timing, etc. Run the test app along with your LightBlue App and watch the constant value be received every 500ms.

 

Jacob W. Torres

 

 

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment