This article will demonstrate how to setup the PSOC 4 BLE in the typical use case of GAP Peripheral/GATT Server as well as demonstrate how to transfer data from the PSOC 4 BLE to another device.
I would highly recommend reading through the CY8CKIT_042_BLE_BLUETOOTH_LOW_ENERGY_BLE_PIONEER_KIT_GUIDE , which is a great introduction to the PSOC 4 BLE Pioneer kit, PSOC Creator and Cysmart.
Either CY8CKIT-042-BLE or CY8CKIT-042-BLE-A . The difference between the two is that the former is compliant with the BLE 4.1 spec and the latter to the BLE 4.2 spec. This difference is irrelevant for the example shown in this article.
GAP and GATT:
The key to understanding how BLE works is to understand the function of the GAP and GATT layers.
GAP (Generic Access Protocol)-The GAP layer determines how BLE devices find and connect to each other. The GAP roles are the GAP Central which typically initiates connections and the GAP Peripheral which accepts connection requests from the GAP Central. There is also the GAP Broadcaster and GAP Observer roles which only deal with advertising events. The article will only deal with the GAP Central and GAP Peripheral roles.
GATT (Generic Attribute Protocol)-The GATT layer determines how two connected BLE devices exchange data.The two roles are the GATT Client and GATT Server. The GATT Client is the device that wants data and will send commands and requests to the GATT Server. The GATT Server is the device that contains data and it will send this data to the GATT Client via either responses, notifications and indications. These methods of transferring data are described in detail in the 'Method of Transferring Data' section later in this article.
How the GATT Server Organizes Data:
Characteristics- A characteristic is a data entity that is compromised of two parts, a characteristic value and characteristic descriptor. A characteristic value is simply a buffer containing data that the GATT Server wants to exchange such as a temperature or heart rate measurement. A characteristic descriptor is a data field which contains a short description detailing what the characteristic value represents. In addition, a characteristic can also contain an optional field called the Client Characteristic Configuration Descriptor which is a buffer that the GATT client can write to in order to enable or disable notifications and indications for a particular characteristic.
Services- A service is simply a collection of characteristics. Typically, the characteristics will share some sort functionality. The purpose of services is to make it easier for the user to retrieve and understand the data on the device. For example, if your BLE device has several characteristics containing temperature sensor measurements, then it might make sense to group them in a single service called "Temp Measurements".
Profiles- A profile is an over-arching concept that describes the application and functionality of a device. A profile will typically contain several services. The Bluetooth spec defines several supported profiles and also allows for the creation of custom profiles. The example in this article uses a custom profile.
Methods of Transferring Data:
Writes- In this method, the GATT Client will send a command to the GATT Server, instructing it to update the value or descriptor of a characteristic.
Reads- In this method, the GATT Client will ask the GATT Server to send the value or descriptor of a characteristic. The GATT Server then sends a response with the requested data.
Notifications- In this method, the GATT Client will enable notifications on the GATT Server . Once notifications are enabled, the GATT Server will send data as it's programming dictates, without any prompting from the GATT Client. The GATT Client will not give any confirmation whether it received the data or not.
Indications- These are basically the same as notifications. However with indications, the GATT Client will send confirmation to the GATT Server that it received the indication.
Example Program Overview:
The goal of this example program is demonstrate how to setup the PSOC 4 BLE as a GAP Peripheral and GATT Central and well as implement the methods of transferring data listed in the section above. To do this, the program uses a custom profile with one custom service called "Number". The "Number" service contains the following characteristics.
Number_Read-This characteristic contains a value that is incremented every time the GATT Client writes to the 'Number_Write" characteristic. It's value can be retrieved by the GATT Client sending a read request to the characteristic value.
Number_Write-Every time a value is written to this characteristic, the value of "Number_Read" increases by one.
Number_Notify-Once the GATT Client enables notifications on this characteristic, the GATT Server will increase the value of this characteristic by one and send the value as a notification. It will continue to increment the value and send notifications until the GATT Client disables notifications for this characteristic.
Number_Indicate-This characteristic functions the same as the "Number_Notify" characteristic, but sends it's values as indications instead of notifications.
Setting Up the BLE Component in PSOC Creator:
To make things easy, I've created a PSOC Creator project with the BLE component already configured. Simply download and unzip the following file, open the workspace, navigate to Main.C and you're ready to go.
Writing the Firmware Walk-through:
Once you have Main.c open, the first thing we need to do is to initialize the variables that we'll use to demonstrate functionality of the BLE component. Modify the main.c file so that it matches the code below.
The next step is to create a callback function to receive and process events from the BLE stack. This function is initialized by the "CyBLE_Start()" api and can be named whatever you like provided the name isn't already reserved. The code to initialize the callback function is shown below.
Next we'll add some code to handle connection events. Modify the callback function as follows:
Next, we need to add a parameter to hold commands sent by the GATT client. At the start of the BLE callback function, before the switch statement, add the following line: "CYBLE_GATTS_WRITE_REQ_PARAM_T *wrReqParam;"
Next, we'll add some code to handle write and write without response requests from a GATT client. Modify the callback function as follows:
Next, within the "if (number !=0)" if statement we just added, we'll add some code to update the number_read attribute. This is all we need to do so add the read functionality to our application because the BLE stack takes care of pretty much all the work for us. Note, it's not necessary to initiate the structure each time, however I did it this way in order to make this example program easier to follow.
The BLE callback function should now look like the following:
Now it's time to enable notifications. Notifications are enabled and disabled by writing to the Client Characteristic Configuration Descriptor of the characteristic that you want to send notifications. Basically, the Client Characteristic Configuration Descriptor (CCCD) is a buffer that is associated with a specific characteristic, that allows the GATT Client to instruct the GATT Server to start or stop sending notifications and indications for that particular characteristic. To add this feature to our example, we'll start by modifying the call back function. The code below will check if the CCCD has been written to and if it has, it will check its value. If the CCCD is equal to 1, then notifications are enabled as per the Bluetooth spec and if the CCCD is greater than 3, an error response is sent.
From there, we need to modify our main function. Outside the main loop, we'll declare a structure "notificationHandle" which will hold all the information we need to send a notification. Within the main loop, we'll include an if statement which will check to see if notifications are enabled and if so, increment the number_notify counter and send its value as a notification.
Indication functionality is added in pretty much the same way as notification functionality, expect we expect a value of 2 for the CCCD as per the Bluetooth spec.
Likewise the modifications to the main function are also similar to the changes made for notifications. The only difference here is that after the indication is sent, we'll disable further indications until a response is received from the GATT Client.
In the callback function, we'll add case to handle the response from the GATT Client. If a response is received, indications are re-enabled.
The final main.c file should look like the following.
Testing the Example:
This example can easily be tested using Cypress's Cysmart software. The steps below detail how to verify this example.
- Start by building the PSOC creator project by pressing "shift +F6" or by selecting it from the 'Build' drop down menu.
- If everything builds correctly, ensure that the PSOC BLE pioneer board is plugged into your PC. Then, program the demo kit by either pressing "Ctrl + F5" or by selecting it from the "Debug" drop down menu.
- Once the board is programmed, insert the BLE Dongle that came provided with the PSOC BLE kit.
- Open Cysmart 1.2 and connect to the dongle as shown below. If you have difficulties connecting to the dongle, I would suggest you take a look at this article: Fixing Connection Issues between the Cypress CySmart Software and the CY5670 USB Dongle
- Once connected, click on the start scan button in the top left of the Cysmart window. After a few seconds, a device called "Peripheral_Example" should appear. You might have to press the reset button on the PSOC 4 BLE pioneer board for the device to appear. Select that device and then hit the connect button.
- Once the device connects, click on the "Discover All Attributes" button. You should then see a screen similar to the following.
- From there, scroll down to handle 0x0013. Select it. Once it is selected, click on the "Read Value" button toward the right of the Cysmart window. This will instruct Cysmart to read the value of the "Number_Right" characteristic which should be 00
- As stated earlier, we need to write to the "Number_Write" service in order to increment the "Number_Read" service's value. To do this in Cysmart, click on handle 0x0010, enter a value in the value window and click the "Write Without Responding" button.
- Now, read the "Number_Read" characteristic as shown in step 7. The value should have incremented by 1. You can repeated steps 8 and 9 to continue incrementing the value.
- Enabling notifications in Cysmart is fairly straight forward, simply write a value of '1' to the Client Characteristic Configuration Descriptor of the "Number_Notify" characteristic which has a handle of 0x0018. Cysmart is a little picky about how the value if formatted, so enter it as shown below.
- Once the value is written, Cysmart should start receiving notifications. You can disable notifications by writing a '0' to the Client Characteristic Configuration Descriptor
- Likewise, indications can be enabled by writing a value of '2' to the Client Characteristic Configuration Descriptor of "Number_Indicate" whose handle is 0x001C.
- Once it the value is written, Cysmart should start receiving indications. As before, you can disable them by writing a '0' to the Client Characteristic Configuration Descriptor.