NAV Navbar

CYW20819 BLE Throughput Measurement – CE226301

This code example demonstrates measuring the BLE throughput at the GATT layer using the CYW20819 Bluetooth SoC with the ModusToolbox™ integrated development environment (IDE).

Requirements

Tool: ModusToolbox IDE 1.1 or later version

Programming Language: C

Associated Parts: CYW20819

Related Hardware: CYW920819EVB-02 Evaluation Kit

Overview

This code example demonstrates measuring the BLE throughput at the GATT layer by continuously sending notifications on a custom characteristic. This application uses User Button 1 on the CYW920819EVB-02 kit to allow you to select either the 1- Mbps or 2-Mbps PHY rate for the device. Two LEDs - red LED (LED2) and yellow LED (LED1) - on the CYW920819EVB-02 kit are used to indicate the device connected/disconnected state and the GATT congestion status respectively.

An iOS/Android mobile device or a PC can act as the BLE Central device which can connect to the Peripheral device, CYW920819EVB-02.

Hardware Setup

This example uses the kit’s default configuration. Refer to the kit guide, if required, to ensure that the kit is configured correctly.

Software Setup

This code example consists of two parts: the GAP Central and the GAP Peripheral. For the GAP Central, download and install the CySmart app for iOS or Android. You can also use the CySmart Host Emulation Tool Windows PC application if you have access to the CY5677 CySmart BLE 4.2 USB Dongle. You can also use other Android or iOS apps that allow you to enable/disable GATT Notifications.

Scan the following QR codes from your mobile phone to download the CySmart app.

iOS Android

Operation

Figure 1. Programming the CYW20819 Device from ModusToolbox

Figure 2. Testing with the CySmart App on Android

Figure 3. Bluetooth stack and application traces on WICED PUART Serial Port

  1. Connect the kit to your PC using the provided USB cable.
  2. The USB Serial interface on the kit provides access to the two UART interfaces of the CYW20819 device – WICED HCI UART and WICED Peripheral UART (PUART). The HCI UART is used only for downloading the application code in this code example; PUART is used for printing the Bluetooth stack and application trace messages.
  3. Import the code example into a new or existing workspace.
    1. Follow the steps in KBA225201 to clone or download the CYW20819 code examples repository from Cypress GitHub portal.
    2. Once you have the repository on your local machine, the BLE throughput code example is in the repository folder at Code-Examples-BT-20819A1-1.0-for-ModusToolbox\CYW920819EVB02\apps\demo\throughput_test. Continue to follow the steps in KBA225201 to import this code example in ModusToolbox IDE with the following changes.
      1. Select the CYW920819EVB-02 evaluation kit in the Choose Target Hardware dialog.
      2. Select the modus.mk file of the throughput_test code example during the Import step in the Starter Application dialog window.

  4. Build and program the application: In the project explorer, select the [App Name]_mainapp project. In the Quick Panel, scroll to the Launches section, and click the [App Name] Build + Program configuration as shown in Figure 1.
  5. To test using the CySmart mobile app, follow the steps below (see equivalent CySmart app screenshots in Figure 2). Refer to the user button description in the design implementation section for a description of how to switch from 1M to 2M PHY on the kit. This is useful when you want to measure throughput on 2M PHY if the mobile phone supports 2M PHY. The screenshots shown are from the Android version of the application; these will vary slightly with the iOS version.
    1. Turn ON Bluetooth on your Android or iOS device.
    2. Launch the CySmart app.
    3. Press the reset switch on the CYW920819EVB-02 kit to start sending advertisements.
    4. Swipe down on the CySmart app home screen to start scanning for BLE Peripherals; your device appears in the CySmart app home screen with the name “TPUT”. Select your device to establish a BLE connection. Once the connection is established, the red LED (LED2) will be ON.
    5. Select GATT DB from the carousel view. (Swipe left or right to change carousel selections).
    6. Select Unknown Service and then select the Characteristic.
    7. Select Notify. CYW920819EVB-02 will start sending GATT notifications to the mobile. The yellow LED (LED1) will be ON while the device is sending notifications and will be OFF intermittently indicating GATT packet congestion.
    8. The device calculates the throughput, and the results are displayed on the PUART terminal as shown in Figure 3.

  6. Open the WICED Peripheral UART (PUART) to view the Bluetooth stack and application traces.
  7. Use a serial terminal application and connect to the PUART port. Configure the terminal application to access the COM port using settings listed in Table 1.

Table 1. WICED Peripheral UART Settings

Setting Value
Baud rate 115200 bps
Data 8 bits
Parity None
Stop 1 bit
Flow control None
New-line for Receive data Line Feed (LF) or Auto setting

Do the following to test using the CySmart desktop application on PC:

  1. Plug the CYW920819EVB-02 (Peripheral device) into your computer.
  2. Build and download the application to the board. The CYW920819EVB-02 will start advertisements.
  3. Open the CySmart desktop application and connect to the CySmart CY5677 dongle (Central device). See the CySmart User Guide to learn how to use the desktop application.
  4. To measure GATT throughput:
    1. Scan and connect to 'TPUT' device.
    2. If asked, click Yes to update the connection parameters. Refer to the Connection Interval section to understand how the connection interval affects the throughput.
    3. Go to the device tab and click Discover all attributes.
    4. Click Enable all Notifications. The GATT throughput results (in bytes per second) will be displayed on the PUART terminal as shown in Figure 3.
    5. Click Disable All Notifications to stop measuring GATT throughput.
    6. Click Disconnect to disconnect from the Central device.

Design and Implementation

In this code example, the CYW20819 device on the kit acts as a GATT Server and GAP Peripheral. Once the device is connected, the Client can send a maximum transmission unit (MTU) Exchange Request to let the Server know about its MTU size. When the Client enables notifications on the Server, the Server sends a maximum Attribute protocol (ATT) payload of 244 bytes of data continuously. If no MTU Exchange is made by the Client, then the Server assumes the default MTU of 23 bytes and thus 20 bytes of data is continuously received by the Client.

CYW920819EVB-02 sends the data over BLE using GATT notifications on a custom characteristic after the notification is enabled by the GATT Client. The throughput is calculated every one second based on the amount of data pushed down successfully from the GATT layer. The throughput results are displayed in the PUART terminal in bytes-per-second.

The Link Layer sends the notification data divided into packets with the Protocol Data Unit (PDU) payload length. The maximum amount of data in one packet can be (251 – 7) bytes where 251 bytes is the maximum PDU payload size, and the 7 bytes consists of the L2CAP header (2-byte Length and 2-byte Channel ID and a 3-byte notification packet header or the ATT header).

The application code and the Bluetooth stack runs on the Arm® Cortex®-M4 core of the CYW20819 SoC. The application-level source files for this code example are listed in Table 2.

Table 2. Application Source Files

File Name Comments
tput.c This file contains the application_start() function, which is the entry point for execution of the user application code after device startup. This file also contains the Bluetooth stack event handler, GATT event handler and timer functions.
tput_bt_cfg.c Theis file contains the runtime Bluetooth stack configuration parameters like device name, advertisement settings, and connection settings.
tput_util.c, tput_util.h These files contain the utility functions such as mapping event ID to String.
cycfg_bt.h, cycfg_gatt_db.c, cycfg_gatt_db.h These files reside in the GeneratedSource folder under the application folder. They contain the GATT database information generated using the Bluetooth Configurator tool.
cycfg_pins.c, cycfg_pins.h, cycfg_connectivity.h, cycfg_notices.h These files reside in the GeneratedSource folder under the application folder. They contain the pin and peripheral configuration information that is generated using the device configurator.
tput_le_coc.c, tput_le_coc.h These files reside in the le_coc folder under the application folder. They enable throughput measurement at the LE Connection-Oriented-Channel (CoC) level. This is disabled by default in this code example. If you want to measure the throughput at the L2CAP layer, enable LE COC in the ModusToolbox IDE by right-clicking the project, and selecting Change Application Settings > LE_COC_SUPPORT.

User Button1 (Button D2 on the Kit)

Switch between 1-Mbps and 2-Mbps PHY via user button1. On power up, CYW920819EVB-02 comes up in 1M PHY mode. When the BLE connection is established, if the peer is 2M PHY capable, it may request the device to set 2M PHY. If the peer allows both 1M and 2M PHY, then on every D2 button press on the kit, CYW920819EVB-02 will switch between the 1M and 2M PHY alternately.

LED1 (LED D1 on the kit): LED1 indicates an active data transmission. It will be OFF when there is congestion or when data transfer is disabled. It will be ON when the device is actively transferring the data.

LED2 (LED D2 on the kit): LED2 is ON when a GAP connection is established; OFF otherwise.

Application Flow

Figure 4. Throughput Application Flow Diagram

The flow of the application is depicted in Figure 4.

Optimize for Maximum Throughput

Some of the known factors that impact the data throughput are explained below.

PHY

The PHY rate being used will have direct impact on the maximum data throughput. You can select either 1-Mbps or 2-Mbps PHY on CYW920819EVB-02. In this code example, you have the option to switch between 1M and 2M PHY via User Button 1 on CYW920819EVB-02 after the BLE connection is established. Not all Central devices support both modes, so it may not be possible to switch for all Central devices.

Connection Interval

A BLE Connection Interval is the time between two data transfer events between the Central and the Peripheral device (in simple words, how often the devices talk). It ranges from 7.5 ms to 4 seconds (with increments of 1.25 ms). It also impacts how many packets can be transferred during one connection event. The higher the value, the more packets can be sent in one connection event. Choosing the connection interval value is purely application-specific. If your application sends large amounts of data at a time and needs good data throughput, then it makes sense to have larger connection interval.

The BLE connection is established with the connection interval value set by the Central device. However, the Peripheral may request a different value. The Central device makes the final decision and chooses a value that may be different from, but closer to, the requested value. In this code example, the Peripheral device requests a connection interval value of 26.25 ms but the value you get will depend on the Central device that you use. The connection interval differs between iOS and Android. It also changes depending on the version of the OS running on the device. This is because the BLE radio may have to attend to other events from the OS and the number of packets sent per connection event may not reach the maximum possible by the BLE stack.

Note that the CySmart desktop application has an option to change the Connection Interval but the CySmart mobile app doesn’t support that option. Refer to Configuring Master Settings section on the CySmart user guide for the detailed instructions on connection parameters. The PUART log will indicate the connection interval once a connection is established whenever it is changed.

Data Length Extension (DLE)

DLE allows the packet to hold a larger payload up to 251 bytes. The DLE feature was introduced in version 4.2 of the Bluetooth SIG specification. Older versions of BLE can support the maximum payload of 27 bytes. The Peripheral (CYW920819EVB-02 of BLE version 5.0) has DLE enabled by default. If the Central device has DLE enabled (in BLE version greater than 4.1), it will get a higher throughput.

ATT Maximum Transmission Unit (MTU)

ATT MTU determines the maximum amount of data that can be handled by the transmitter and receiver as well as how much they can hold in their buffers. The minimum ATT MTU allowed is 27 bytes. This allows a maximum of 20 bytes of ATT payload (3 bytes are used for the ATT header and 4 bytes for the L2CAP header). There is no limit on the maximum MTU value.

Because CYW920819EVB-02 has DLE enabled by default, it can transfer up to 251 – 4 (L2CAP header) = 247 bytes. So, the maximum ATT payload data will be 247 – 3 (ATT header) which comes up to 244 bytes. If the ATT MTU is exactly 247 bytes, then the ATT data will fit into a single packet. If the MTU is greater than 247 bytes, then the MTU will span multiple packets causing the throughput to go down because of packet overhead and timing in between the packets. This example application sets the MTU to 244 by default, but it can be changed by varying the value for the macro GATT_NOTIFY_BYTES_LEN in tput.c.

Packet Overhead

Figure 5. LE Packet Format

As shown in Figure 5, the LE packet includes many packet header bytes which get added up in each layer that are not accounted for in the application data throughput. To minimize the packet overhead, try to configure the ATT MTU size in such a way that at any time the ATT payload data will fit in a single LE packet. In this code example, the ATT MTU size used is 244 bytes, which exactly matches with the ATT payload data size of 244 bytes.

Resources and Settings

Figure 6. Device Configurator

This section explains the ModusToolbox resources and their configuration as used in this code example. The ModusToolbox IDE stores the configuration settings of the application in the design.modus file. This file is used by the graphical configurators, which generate the configuration firmware. This firmware is stored in the application’s GeneratedSource folder.

Figure 6 shows the Device Configurator settings for this code example. The Device Configurator is used to enable/configure the peripherals and the pins used in the application. To launch the Device Configurator, double-click the design.modus file or click Configure Device in the Quick Panel. Any time you make a change in the Device Configurator, ensure that you save the updated configuration.

The code example uses only the highlighted options in Figure 6 for the application.

Peripherals: The design uses the Bluetooth and PUART peripherals which are enabled under the Peripherals section as shown in Figure 6.

Figure 7. GATT Database View in BLE Configurator

Bluetooth Configurator: The Bluetooth Configurator is used for generating/modifying the BLE GATT database. To launch the Bluetooth Configurator from the Device Configurator window, click on the Bluetooth resource under the Peripherals section, and then click on the Launch Bluetooth Configurator button under the Bluetooth-Parameters window (as shown in callouts A, B in Figure 6). The Bluetooth Configurator for this code example is shown in Figure 7. Note that the custom GATT Service named TPUT has been added in Figure 7. Any time you make a change in the Bluetooth Configurator, ensure you save the changes.

Table 3. Pin Mapping Details

Pin Number Alias Purpose Settings
P26 LED2 Mapped to the red LED (LED2) on the kit. Indicates BLE Advertising/Connected state of the BLE Peripheral device. See Figure 8
P27 LED1 Mapped to the yellow LED (LED1) on the kit. Indicates the GATT Notifications being sent to the Central.
P00 BUTTON1 Mapped to the User Button (D2) on the kit. See Figure 9
P32 PUART_TX Tx pin of PUART peripheral. See Figure 10
P37 PUART_RX Rx pin of PUART peripheral. See Figure 11

Pins: The pins used in the application are enabled in the Pins section of the Device Configurator as shown in Figure 6. Table 3 provides more information on these pins.

Figure 8. LED Pin Settings

Figure 9. BUTTON1(D2) Settings

Figure 10. PUART Tx Pin Settings

Figure 11. PUART Rx Pin Settings

Code Example

The BLE_Throughput demo app demonstrates how to measure and achieve better throughput via GATT notifications on a CYW920819EVB-02 kit. It sends GATT notifications every millisecond and calculates the throughput. GATT notifications are sent only when notifications are enabled. This example also provides an option to switch between 1M and 2M PHY via user button1.

On power up, CYW920819EVB-02 comes up in 1M PHY mode. Once a BLE connection is established, a peer with 2M PHY support may request the device to switch to the 2M PHY. If the peer allows both 1M and 2M PHY, then on every press of user button SW3, CYW920819EVB-02 switches between 1M and 2M PHY alternatively.

BLE Initialization (tput.c)

APPLICATION_START()
{
    wiced_transport_init(&transport_cfg);

    wiced_set_debug_uart(WICED_ROUTE_DEBUG_TO_PUART);

    wiced_bt_stack_init(tput_management_callback, &tput_bt_cfg_settings,
                                                 tput_bt_cfg_buf_pools);

}

The function wiced_transport_init() initializes and configures the transport interface and registers callback handlers to be invoked when receiving data or initialization is completed. This is used to enable the debug prints either on the PUART or HCI UART using WICED_ROUTE_DEBUG_TO_PUART or WICED_ROUTE_DEBUG_TO_HCI_UART. wiced_debug_uart_types_t lists the debug print options.

The result function is wiced_result_t, which will return WICED_BT_SUCCESS on successful initialization or WICED_BT_FAILED if an error occurs.

The function wiced_bt_stack_init() initializes the Bluetooth controller and stack, and registers a callback for Bluetooth event notifications. The function returns wiced_result_t, which will return WICED_BT_SUCCESS on successful initialization of the Bluetooth stack or WICED_BT_FAILED if an error occurs.

The tput_management_callback() function is called to handle BLE stack events. Based on these events, you will have to add code or call functions to take necessary actions.

Stack Event Handler (tput.c)

wiced_result_t tput_management_callback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data)
{
       switch (event)
    {
        case BTM_ENABLED_EVT:
            tput_init();
            break;

        case BTM_USER_CONFIRMATION_REQUEST_EVT:
            wiced_bt_dev_confirm_req_reply(WICED_BT_SUCCESS, p_event_data>user_confirmation_request.bd_addr);
            break;

        case BTM_PASSKEY_NOTIFICATION_EVT:
            wiced_bt_dev_confirm_req_reply(WICED_BT_SUCCESS,
p_event_data->user_passkey_notification.bd_addr);
            break;

        case BTM_PAIRING_IO_CAPABILITIES_BLE_REQUEST_EVT:
            p_event_data->pairing_io_capabilities_ble_request.local_io_cap = BTM_IO_CAPABILITIES_NONE;
            p_event_data->pairing_io_capabilities_ble_request.oob_data     = BTM_OOB_NONE;
            p_event_data->pairing_io_capabilities_ble_request.auth_req     = BTM_LE_AUTH_REQ_NO_BOND;
            p_event_data->pairing_io_capabilities_ble_request.max_key_size = 0x10;
            p_event_data->pairing_io_capabilities_ble_request.init_keys    = BTM_LE_KEY_PENC|BTM_LE_KEY_PID|BTM_LE_KEY_PCSRK|BTM_LE_KEY_LENC;
            p_event_data->pairing_io_capabilities_ble_request.resp_keys    = BTM_LE_KEY_PENC|BTM_LE_KEY_PID|BTM_LE_KEY_PCSRK|BTM_LE_KEY_LENC;
            break;

        case BTM_PAIRING_COMPLETE_EVT:
            p_info =  &p_event_data->pairing_complete.pairing_complete_info.ble;
            wiced_bt_get_identity_address (tput_conn_state.remote_addr, bda );
            break;

        case BTM_BLE_SCAN_STATE_CHANGED_EVT:
            /* Insert code */
            break;

        case BTM_SECURITY_REQUEST_EVT:
            wiced_bt_ble_security_grant(p_event_data->security_request.bd_addr, WICED_BT_SUCCESS);
            break;

        case BTM_BLE_ADVERT_STATE_CHANGED_EVT:
            p_mode = &p_event_data->ble_advert_state_changed;
            if (*p_mode == BTM_BLE_ADVERT_OFF)
            {
                tput_advertisement_stopped();
            }
            break;

        case BTM_BLE_PHY_UPDATE_EVT:
            phy_config = p_event_data->ble_phy_update_event.tx_phy;
            if (phy_config == phy_1m_2m)
            {
                /* Insert code */

            }
            else
            {
                /* Insert code */

            }
            break;

        case BTM_BLE_CONNECTION_PARAM_UPDATE:
            if(WICED_SUCCESS == p_event_data->ble_connection_param_update.status)
            {
                conn_interval = (p_event_data->ble_connection_param_update.conn_interval) * CONN_INTERVAL_MULTIPLIER;

            }
            else
            {
            }
            break;

        default:
            break;
    }

    return (result);
}

The BTM_ENABLED_EVT event is triggered once BLE stack initialization is complete. After this event, the main application will start its execution by calling the function tput_init(). The function tput_init() initializes and registers the button interrupt, timers, GATT database, and starts undirected advertisement using the function wiced_bt_start_advertisements(BTM_BLE_ADVERT_UNDIRECTED_HIGH, BLE_ADDR_PUBLIC, NULL).

At every timeout value of the timer, a notification will be sent out. The function tput_set_advertisement_data() is used to set the advertisement parameters and make the device discoverable. wiced_bt_gatt_register() is also called for registering GATT events callback handler tput_gatts_callback().

BTM_USER_CONFIRMATION_REQUEST_EVT and BTM_PASSKEY_NOTIFICATION_EVT events are triggered to confirm the numeric value for pairing when WICED_BT_SUCCESS is received.

BTM_PAIRING_IO_CAPABILITIES_BLE_REQUEST_EVT event is triggered when I/O capabilities are requested for BLE pairing to happen. The slave can check peer I/O capabilities in the event data wiced_bt_dev_ble_io_caps_req_t before updating with local I/O capabilities.

BTM_PAIRING_COMPLETE_EVT event is received when the pairing process is completed successfully. wiced_bt_get_identity_address() is used to return the identity address of the given device.

BTM_BLE_SCAN_STATE_CHANGED_EVT is called when BLE scan state switching occurs. When scanning stops, you will see BTM_BLE_SCAN_TYPE_NONE. High-duty-cycle scan is indicated by BTM_BLE_SCAN_TYPE_HIGH_DUTY and low-duty-cycle scan is indicated by BTM_BLE_SCAN_TYPE_LOW_DUTY.

The BTM_SECURITY_REQUEST_EVT event received for a security request, which is responded by wiced_bt_ble_security_grant(), which either grants or denies the pairing attempt by the peer device. BTM_SUCCESS is used to give access, BTM_MODE_UNSUPPORTED is used to deny pairing and BTM_REPEATED_ATTEMPTS to indicate an already paired state.

The BTM_BLE_ADVERT_STATE_CHANGED_EVT is called when the advertisement state changes. For fast advertisement, the return value is 3 indicating BTM_BLE_ADVERT_UNDIRECTED_HIGH advertisement mode. BTM_BLE_ADVERT_OFF is used to indicate the stop of advertisements.

The BTM_BLE_PHY_UPDATE_EVT event is for any updates in the physical link between 1M PHY mode or 2M PHY mode.

The BTM_BLE_CONNECTION_PARAM_UPDATE event indicates connection parameter updates like updates in connection interval or supervision timeout by using the event data wiced_bt_ble_connection_param_update_t.

GATT Event Handler (tput.c)

tput_gatts_callback(wiced_bt_gatt_evt_t event, wiced_bt_gatt_event_data_t *p_data)
{
    switch(event)
    {
    case GATT_CONNECTION_STATUS_EVT:
        result = tput_gatts_conn_status_cb(&p_data->connection_status);
        break;
    case GATT_ATTRIBUTE_REQUEST_EVT:
        result = tput_gatts_req_cb(&p_data->attribute_request);
        break;
    default:
        break;
    }
    return result;
}

The tput_gatts_callback() function is called after BT stack initialization to handle GATT events from the BT stack. The function returns wiced_bt_gatt_status_t with different GATT status codes. For example, WICED_BT_GATT_ILLEGAL_PARAMETER is returned with value '1' to indicate an illegal parameter. The complete list of codes can be found in wiced_bt_gatt.h.

The GATT_CONNECTION_STATUS_EVT event is triggered when GATT connection status is changed. The tput_gatts_conn_status_cb() function is called to check the connection status with a particular connection ID.

The GATT_ATTRIBUTE_REQUEST_EVT event is triggered when a GATT read event GATTS_REQ_TYPE_READ or a GATT write event GATTS_REQ_TYPE_WRITE occurs. These events are handled by the function tput_gatts_req_cb(). tput_gatts_req_read_handler() and tput_gatts_req_write_handler() are called accordingly depending on request type to process read or write commands.

Connection Up

wiced_bt_gatt_status_t tput_gatts_connection_up(wiced_bt_gatt_connection_status_t *p_status)
{
    tput_conn_state.conn_id = p_status->conn_id;
    memcpy(tput_conn_state.remote_addr, p_status->bd_addr, sizeof(BD_ADDR));

    result =  wiced_bt_start_advertisements(BTM_BLE_ADVERT_OFF, BLE_ADDR_PUBLIC, NULL);
    wiced_bt_l2cap_update_ble_conn_params(p_status->bd_addr, CONNECTION_INTERVAL,
                                       CONNECTION_INTERVAL, 0, BLE_CONN_TIMEOUT);
    return result;
}

The tput_gatts_connection_up() function is invoked when a GATT connection is established. The connected device address is saved and connection handler is updated. Advertisement is stopped using wiced_bt_start_advertisements(BTM_BLE_ADVERT_OFF, BLE_ADDR_PUBLIC, NULL). The Connection interval is updated if required using wiced_bt_l2cap_update_ble_conn_params(). The function returns the GATT status wiced_bt_gatt_status_t with different GATT codes which are listed in wiced_bt_gatt.h.

Connection Down

tput_gatts_connection_down(wiced_bt_gatt_connection_status_t *p_status)
{
    memset(tput_conn_state.remote_addr, 0, sizeof(BD_ADDR));
    tput_conn_state.conn_id = 0;

    result =  wiced_bt_start_advertisements(BTM_BLE_ADVERT_UNDIRECTED_LOW, BLE_ADDR_PUBLIC, NULL);

    tput_hostinfo.characteristic_client_configuration = 0;

    if ((puAttribute = tput_get_attribute(HDLD_TPUT_NOTIFY_DESCRIPTOR)) != NULL)
    {
        memcpy(puAttribute->p_data,
                (uint8_t *)&tput_hostinfo.characteristic_client_configuration,
                puAttribute->max_len);
    }

    WICED_SUPPRESS_WARNINGS(result);

    return result;
}

The tput_gatts_connection_down() function is invoked when a GATT disconnection occurs. Once disconnection is done, undirected low advertisement is started using the wiced_bt_start_advertisements(BTM_BLE_ADVERT_UNDIRECTED_LOW, BLE_ADDR_PUBLIC, NULL) function so that the peer can connect when it wakes up. GATT notifications are disabled and updated in the GATT database. The function returns the GATT status wiced_bt_gatt_status_t with different GATT codes which are listed in wiced_bt_gatt.h.

Send Notifications

static void tput_send_notification(void)
{
    buf_left = wiced_bt_ble_get_available_tx_buffers();
    if (buf_left > MINIMUM_TX_BUFFER_LEN)
    {
        status = wiced_bt_gatt_send_notification(tput_conn_state.conn_id,
                                                  HDLC_TPUT_NOTIFY_VALUE,
                                          sizeof(tput_char_notify_value),
                                                 tput_char_notify_value);
        if (status == WICED_BT_GATT_SUCCESS)
        {
            numBytesTx += sizeof(tput_char_notify_value);
            wiced_hal_gpio_set_pin_output(CONGESTION_LED, GPIO_PIN_OUTPUT_LOW);
        }
        else
        {
            wiced_hal_gpio_set_pin_output(CONGESTION_LED, GPIO_PIN_OUTPUT_HIGH);
        }
    }
    else
    {
        failed_to_send++;
        wiced_hal_gpio_set_pin_output(CONGESTION_LED, GPIO_PIN_OUTPUT_HIGH);
    }
}

The available number of BLE transmit buffers is checked using wiced_bt_ble_get_available_tx_buffers(); if the value is greater than the minimum length required, GATT notifications are sent every millisecond using wiced_bt_gatt_send_notification(). LED 1 is turned ON to indicate active data transmission and turned OFF when there is congestion or failed data transfer.

Send Message

void tput_send_message(void)
{

    if (!tput_hostinfo.characteristic_client_configuration)
    {
        WICED_BT_TRACE("\r####### TPUT: client not registered for notification/indication #######");
        return;
    }
    if (tput_hostinfo.characteristic_client_configuration &
                           GATT_CLIENT_CONFIG_NOTIFICATION)
    {
        WICED_BT_TRACE("\r####### TPUT: client registered for notification #######");

        wiced_bt_gatt_send_notification(tput_conn_state.conn_id,
                                         HDLC_TPUT_NOTIFY_VALUE,
                                 sizeof(tput_char_notify_value),
                                        tput_char_notify_value);
    }
}

The tput_send_message() function is used to send notifications only if the client has registered for notifications or indications. Notifications are sent only if the notification bit is set in the CCCD. This function is currently not being called in the code, but can be used to send notifications only if the client has registered for notifications.

Bluetooth Configuration (tput_bt_cfg.c)

This file is used to declare the wiced_bt core stack configuration parameters and wiced_bt_stack buffer pool configurations.

Utility Functions (tput_util.c)

Parse BLE Event Management Code to String

const char* getStackEventStr(wiced_bt_management_evt_t event)
{
    if (event >= sizeof(eventStr) / sizeof(char*))
    {
        return "** UNKNOWN **";
    }

    return eventStr[event];
}

The function getStackEventStr() is used to parse BLE event management code to string. The return value is a pointer to the BLE management string mapped to the corresponding event code.

Parse BLE Advertisement Status Code to String

const char* getAdvStatusStr(wiced_bt_ble_advert_mode_t event)
{
    if (event >= sizeof(advStr) / sizeof(char*))
    {
        return "** UNKNOWN **";
    }

    return advStr[event];
}

The function getAdvStatusStr() is used to parse BLE advertisement status code to string. The return value is a pointer to the BLE advertisement status string mapped to the corresponding event code.

Locate GATT Attribute Descriptions

gatt_db_lookup_table_t* tput_get_attribute(uint16_t handle)
{
    int i;
    for (i = 0; i < app_gatt_db_ext_attr_tbl_size; i++)
    {
        if (app_gatt_db_ext_attr_tbl[i].handle == handle)
        {
            return (&app_gatt_db_ext_attr_tbl[i]);
        }
    }
    return NULL;
}

The function tput_get_attribute() is to locate the GATT attribute descriptions and return a pointer to the BLE GATT attribute handle. This is used to check if the attribute handle is present in the GATT database lookup table.