Bluetooth 5 Lab Manual

Introduction

This document demonstrates how to use the Bluetooth 5 features supported in the BLE SDK 2.13 using the GCC compiler and Simplicity Studio IDE.

The focus of this training session will be on BT5 features supported in BLE SDK 2.13.

Topics covered

Getting Started

Review the following material before starting the Bluetooth 5 labs. Ensure that you have the correct hardware and software to successfully complete the labs.

Hardware Requirements

Software Requirements

Software Installation

  1. Install Simplicity Studio v4 (https://www.silabs.com/products/development-tools/software/simplicity-studio)

    1. Install Device Support by clicking on tab “Select by Product Group”.

    2. Click on Wireless Products. Click Next.

  2. Install Protocol SDKs by clicking menu bar Help -> Update Software. Click on tab for “SDKs” in Package Manager window

    1. Select and Install Gecko Platform – v2.7

    2. Select and Install Bluetooth SDK – v2.13

  3. Install Silicon Labs EFR Connect app from a mobile app store: Google Play or Apple App Store

Add 2M PHY Connections to an Application

Create a Project Using Simplicity Studio IDE

Start by creating an soc-empty sample application.

  1. Click on the Simplicity IDE button in the upper right corner to return to the IDE perspective.

  2. Select File -> New -> Project in the menu bar.

  3. In the Create Project window, Click on Silicon Labs AppBuilder project and click next.

  4. Click Bluetooth SDK and click next.

  5. Click Bluetooth SDK 2.13 and click next.

  6. Click SOC - Empty and click next.

  7. Enter soc-bt5-server for the project name and click next.

  8. Select your target board from the list and turn off all configurations except GNU ARM v7.2.1 and click finish.

    Creating a new project using Simplicity Studio IDE

  9. Drag and drop app-server.c into the project folder and delete app.c.

  10. Open app.h and enable DEBUG_LEVEL by changing the value from 0 to 1.

Add 2M PHY Service to GATT

  1. Open the visual GATT editor by double clicking project’s .isc file and click on the Custom BLE GATT.

  2. Create a new service by clicking on the Create new item icon in upper right of configurator. Select New Service (now named as Service).

  3. Under General settings, set the Name of the service to 2mphy_test.

  4. Give it the following UUID: a4aabbb3-4de2-41c6-8a3f-3fae9214cd49

This is an important step because the client will look for a server advertising a service with this custom UUID.

  1. Check the Advertise service box.

  2. Create a characteristic for this service by clicking on the Create new item icon and selecting New Characteristic. Note that the 2mphy_test has to be selected before Characteristic can be created.

  3. Under General settings, set the Name of the characteristic to sample_data.

  4. Under Properties, set the information to only include Read with Requirement = Optional and State = True.

  5. Save .isc GATT configurator and Click Generate to update changes to the GATT files.

Add Event Handler Code for 2M PHY Connections

Add an event handler in app-server.c for the le_connection_phy_status event. Copy the following code and put it below the comment /* LAB TASK 2M PHY connection: phy status handler */.

case gecko_evt_le_connection_phy_status_id:
    printLog("now using the %s PHY\r\n", getPhyName(evt->data.evt_le_connection_phy_status.phy).string);
break;

Add Event Handler for Scan Request Reporting

Another feature of Bluetooth 5 is the added ability to report scan requests. To add this event handler, paste in the following code after the comment, which reads /*LAB TASK 2M PHY connection: scan request reporting */.

case gecko_evt_le_gap_scan_request_id:
    printLog("received scan request from:   %02x:%02x:%02x:%02x:%02x:%02x\r\n",
    evt->data.evt_le_gap_scan_request.address.addr[5],
    evt->data.evt_le_gap_scan_request.address.addr[4],
    evt->data.evt_le_gap_scan_request.address.addr[3],
    evt->data.evt_le_gap_scan_request.address.addr[2],
    evt->data.evt_le_gap_scan_request.address.addr[1],
    evt->data.evt_le_gap_scan_request.address.addr[0]);
break;

This is a purely informative event and no action is required here. This event handler simply prints out the address of the device requesting the scan response. To enable this reporting, also add a call to the following:

gecko_cmd_le_gap_set_advertise_report_scan_request(HANDLE_DEMO,true);

add this call after the comment /*LAB TASK 2M PHY connection: enable scan request */.

Program Starter Kit with 2M PHY Server Application

  1. Click Build icon in the tool bar at the top of the Simplicity IDE. The project will compile based on its build configuration. (NOTE: You need to select the project in the Project explorer view on left)
  2. Press the Debug icon in the tool bar. This will flash the project onto the board if it was successfully built. This only updates the program memory.

  3. Once the project is flashed, the Debug perspective is shown and by default the application execution is stopped at main()-function. Press the Resume icon in the tool bar to have the application start.

Program Client with 2M Capable Client Application

Now that a Server (aka peripheral) application is set up, build a client which can connect to this server.

As with the server application, the source code for the client is provided (app-client.c).

  1. Create a new project, as you did in section above and name it soc-bt5-client.

  2. Replace app.c with app-client.c. A few helper functions have been added to this template, which are not related to Bluetooth 5 features.

  3. Copy src directories from C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v2.7\platform\emdrv\gpiointerrupt and put it in platform\emdrv\gpiointerrupt\ folder in your project.

  4. System Boot event handler is started by adding a startup message to find out when the device has started and the setup for scanning. Paste in the following code for the system boot event, right after the comment /* LAB TASK 2M PHY CONNECTION: start scanning */ in app-client.c.

     bootMessage(&(evt->data.evt_system_boot));
     printLog("BT5 test client started\r\n");
     /*set the discovery type for both PHYs to passive */
     gecko_cmd_le_gap_set_discovery_type(le_gap_phy_1m|le_gap_phy_coded,0);
    
     /* 200 ms scan window min/max*/
     gecko_cmd_le_gap_set_discovery_timing(le_gap_phy_1m|le_gap_phy_coded,320,320);
    
     /* start listening for devices to connect to */
     gecko_cmd_le_gap_start_discovery(scanning_phy,le_gap_discover_generic);
     gecko_cmd_le_gap_set_discovery_extended_scan_response(true);
  5. The client looks for the server by the service it advertises. Add the following code just after the comment /* LAB TASK 2MPHY CONNECTION: service UUID */.

     static const uint8 silabs_2mphy_uuid[16] = {0xa4,0xaa,0xbb,0xb3,0x4d,0xe2,0x41,0xc6,0x8a,0x3f,0x3f,0xae,0x92,0x14,0xcd,0x49};
  6. A scan response event handler is next. The event used here is a new event available starting in SDK v2.10. This event is enabled by calling gecko_cmd_le_gap_set_discovery_extended_scan_response(true); as done above in step 4. Add the following code just after the comment /* LAB TASK: 2M PHY CONNECTION: scan response event handler */.

    case gecko_evt_le_gap_extended_scan_response_id:
    {
        for(int index = 0; index < evt->data.evt_le_gap_extended_scan_response.data.len;){
            if(evt->data.evt_le_gap_extended_scan_response.data.data[index+1] == 0x07){
                if(check_uuid(&evt->data.evt_le_gap_extended_scan_response.data.data[index+2], 16) == true){
                    /*stop scanning for now*/
                    gecko_cmd_le_gap_end_procedure();
        /* and connect to the advertising device using whatever PHY we're scanning on*/
        gecko_cmd_le_gap_connect(evt->data.evt_le_gap_extended_scan_response.address, evt->data.evt_le_gap_extended_scan_response.address_type,scanning_phy);
        break;
                }
            }
         index += evt->data.evt_le_gap_extended_scan_response.data.data[index]+1;
        }
    }
    break;
  7. The two buttons on the WSTK are used these to control the following parameters PB0 to control the PHY used for scanning, and PB1 to control the desired PHY once a connection has been established. To accomplish, use the Bluetooth stack’s external sign mechanism which requires an event handler. Paste in the following immediately after the comment /* LAB TASK: 2M PHY CONNECTION: external signal handling event */.

     case gecko_evt_system_external_signal_id:
           /* */
         if (evt->data.evt_system_external_signal.extsignals==1){
               printLog("Switching scanning PHY\r\n");
               gecko_cmd_le_gap_end_procedure();
               if(scanning_phy == le_gap_phy_1m){
                   scanning_phy = le_gap_phy_coded;
                   phy_index = 2;
               }
               else if (scanning_phy == le_gap_phy_coded){
                   scanning_phy = le_gap_phy_1m;
               }
               printLog(" Starting scanning on %s PHY \r\n", getPhyName(scanning_phy).string);
               gecko_cmd_le_gap_start_discovery(scanning_phy, le_gap_discover_generic);
         }
         else if (evt->data.evt_system_external_signal.extsignals==2){
    
               //use PB1 to increment the desired PHY
               phy_index = (phy_index+1)%4;
               desired_phy = supported_phys[phy_index];
               gecko_cmd_le_connection_set_preferred_phy(connection, desired_phy,  le_gap_phy_1m|le_gap_phy_2m|le_gap_phy_coded );
    
         }
     break;
  8. Open app.h and enable DEBUG_LEVEL by changing the value from 0 to 1. Include also #include "gpiointerrupt.h" in the same file.

  9. Build the project and flash the resulting hex file to the second WSTK.

Open Consoles to Display 2M Status

The two Bluetooth 5 devices will establish a 1M PHY connection. After a connection is established, the PHY can be changed by pressing PB1 on the client WSTK. If the selected PHY is not supported by the remote server, the connection will fall back to the 1M PHY.

The status of the connections is printed to debug terminals.

  1. Open 2 consoles to show these status messages. Right click the WSTK in the debug adapters perspective as shown, then select the serial1 tab, place the cursor in the text entry field at the bottom, and press enter.

  2. Press reset on both boards to see the startup messages and confirm that both applications are running.

  3. After a connection is formed, press PB1 on the Client board to switch to the 2 Mbps PHY.

  4. The client will now display a message indicating that the 2Mbps PHY is in use.

Compare Server PHY Connection of Mobile Device vs. 2M PHY Client

To establish a 4.2 connection with the server, switch off the client WSTK then restart the server and connect to it using the EFR Connect app in the mobile. Click on the Bluetooth Browser and select the “Empty Ex” server. A 1M PHY connection is established as it loads the GATT information.

Add Multiple Advertisement Sets to an Application

Bluetooth 5 supports multiple advertisements each with its own data and transmitting power and timing parameters. This section explains how an application can simultaneously send out a non-connectable iBeacon advertisement as well as a connectable Eddystone advertisement.

The project loaded in section Add 2M PHY connections to an application, bt5-server, will be modified to demonstrate the new features for Advertisement sets.

Increase Number of Advertisers

max_advertisers field in the Bluetooth configuration structure, which is found in main.c file, configures the maximum number of advertisers. Its value can be overwritten in app-server.c. Put the following code next to /* LAB TASK MULTIPLE ADVT: max_advertisers */

pconfig->bluetooth.max_advertisers = 3;

This will initialize the Bluetooth stack to support the specific amount of advertisements.

Configure Beacons and Enable after Boot Event

  1. In app-server.c go to the location marked by the comment /* LAB TASK MULTIPLE ADVT: iBeacons */ and uncomment the following line bcnSetupAdvBeaconing(); If you examine the contents of this function, you’ll see a new API gecko_cmd_le_gap_set_advertise_tx_power(). This API allows you to set the TX power used in just this advertiser without affecting other advertisers nor the TX power used in connections. Do this first because it sets the power.

  2. Include #include "infrastructure.h" into app.h. Enable iBeacon also by setting #define IBEACON to 1 in app-server.c.

  3. In app-server.c, go to the code section below the comment /* LAB TASK MULTIPLE ADVT: modify your custom URL */ and modify the characters for a custom URL you would like for the physical Web advertisement.

  4. Determine the new value with the new URL and modify the length and the characters for the URL.

     static uint8_t eddystone_data[] = {
         0x03, //Length of service list
         0x03, //service list
         0xAA, 0xFE, //Eddystone ID
         0x10, //length of service data = 6 plus length of URL (silabs.com)  that is 10 = 16 = 0x10
         0x16, //service data
         0xAA, 0xFE, //Eddystone ID
         0x10, //frame type Eddystone-URL
         0x00, // tx power
         0x00, //http://www.
         's','i','l','a','b','s','.','c','o','m'
     };
  5. Navigate to the Event Handler section of code in the main() routine.

  6. Modify the case statement for gecko_evt_system_boot_id after the existing iBeacon instructions. Insert the following code at the location marked by comment: /* LAB TASK MULTIPLE ADVT: EddyStone */

    /* EddyStone*/
     gecko_cmd_le_gap_bt5_set_adv_data(HANDLE_EDDYSTONE, ADV_PKT, 30, eddystone_data);
     gecko_cmd_le_gap_set_advertise_configuration(HANDLE_EDDYSTONE,0x01);
     gecko_cmd_le_gap_set_advertise_timing(HANDLE_EDDYSTONE,160,160,0,0);
     gecko_cmd_le_gap_set_advertise_channel_map(HANDLE_EDDYSTONE,0x07);
     gecko_cmd_le_gap_start_advertising(HANDLE_EDDYSTONE,le_gap_user_data, le_gap_non_connectable);

Build and Flash the Application

  1. Click the Build icon in the tool bar at the top of the Simplicity IDE. The project will compile based on its build configuration. (NOTE: You need to select the project in the Project explorer view on left).

  2. Press the Debug icon in the tool bar. This will flash the project onto the board if it was successfully built. This only updates the program memory.

  3. After the project is flashed, the Debug perspective will be shown. Press the Resume icon in the tool bar to start the application.

Use Mobile App to View Multiple Advertisements

  1. Open the BlueGecko app on a smartphone and tap the Bluetooth Beaconing tab.

  2. Multiple beacons broadcast from one device. An iBeacon and Eddystone beacon are displayed.

  3. Install the mobile App Beacon Scanner by Nicolas Bridoux from the Google Playstore if you have an Android phone or eBeacon by Lifestyle from the Apple Appstore. These apps scan for Physical Web advertisements i.e., Eddystone.

  4. Open the Beacon app or enable notifications. The Eddystone URL is shown. You can tap the ‘visit website’ link to visit www.silabs.com.

Extended Advertisements

Getting Started with Extended Advertisements

This section explains extended advertisements. This type of advertisement is used by both the LE Coded PHY for any length of advertising packet and by the 1M PHY for packets longer than 31 bytes. LE coded PHY is discussed first.

  1. Paste in the following code after the comment marked /* LAB TASK EXTENDED ADVT: 4th advertisement */.

     gecko_cmd_le_gap_set_advertise_timing(HANDLE_EXTENDED,160,160,0,0);
     gecko_cmd_le_gap_set_advertise_phy(HANDLE_EXTENDED,le_gap_phy_coded,le_gap_phy_coded);
     gecko_cmd_le_gap_start_advertising(HANDLE_EXTENDED,le_gap_general_discoverable, le_gap_undirected_connectable);
  2. Change the maximum number of advertisers setting to 4, as you did in section Increase number of advertisers.

  3. Build the project and download it to the target board as you have in previous sections. Now the server application should be broadcasting 4 beacons: a connectable 1M advertisement, an iBeacon, an Eddystone beacon, and a connectable 125k coded PHY advertisement.

  4. However, this section of code has an intentional error built into it. The task here is to find out what’s wrong and fix it. Each of the BGAPI functions returns an error code, which you can output using printLog. See the BGAPI reference manual for error code definitions and for information about acceptable advertising configurations. You may want to turn off scan request reporting here to limit the number of messages being sent to the console and comment out the code added in the section Add Event Handler for Scan Request Reporting.

  5. After you’ve fixed the bug, you can move on to the client. Here, you can add code to test the packet type to check if the advertisement was of the extended type and print the PHY used for the primary and secondary advertisements. This information is used to determine which PHYs are actually being used by the advertiser. Paste in the following at the very beginning of the extended scan response event handler.

     if(0x80 & evt->data.evt_le_gap_extended_scan_response.packet_type){
         printLog("extended advertising packet primary advertisement on %s PHY and secondary advertisment on %s PHY\r\n",
             getPhyName(evt->data.evt_le_gap_extended_scan_response.primary_phy).string,
             getPhyName(evt->data.evt_le_gap_extended_scan_response.secondary_phy).string);
    
             /* LAB TASK ANONYMOUS ADVERTISEMENT: check and verify reception of anonymous advertising */
    
             /*LAB TASK EXTENDED ADVT: Long Advertising Packet and the 2Mbps PHY */
     }
  6. As a bonus exercise, you can also add code here to print out information about the address type and the bond handle. Do the following:

  7. After the code in step 5 (and optionally step 6) has been added, build the project and flash it to client board.

  8. Temporarily power down the server WSTK to prevent the client from connecting to it automatically.

  9. Build the application and download to the target as before.

  10. Press PB0. You’ll see a message on the console indicating that scanning is done on the LE Coded PHY (125k).

  11. Power up the server WSTK.

  12. The client’s console will now connect when it finds the desired service UUID being advertised.

  13. Press PB1 to switch the PHY. Any of the supported PHYs can be selected by pressing PB1 to cycle through the list. The server and client consoles each display the PHY currently in use. Note that the 500k PHY is not supported in this example.

Long Advertising Packet and the 2Mbps PHY

Another feature of extended advertising is the ability to set the PHY for the primary and secondary advertisements independently. This gives the user the ability to use the 2Mbps PHY to save energy.

  1. Go to the Visual GATT Editor of your server application and change the device name to Extended Advertising Test Device and change the length parameter to 40.

  2. In app-server.c, find the comment /* LAB TASK EXTENDED ADVT: 4th advertisement */ and make the following change to the call gecko_cmd_le_gap_set_advertise_phy(). Add also configurations to set the transmission power and include it in the advertising packets just before start advertising command.

     gecko_cmd_le_gap_set_advertise_phy(HANDLE_EXTENDED,le_gap_phy_coded, le_gap_phy_2m);
     gecko_cmd_le_gap_clear_advertise_configuration(HANDLE_EXTENDED,0x01);
     gecko_cmd_le_gap_set_advertise_configuration(HANDLE_EXTENDED,0x08);
     gecko_cmd_le_gap_set_advertise_tx_power(HANDLE_EXTENDED,100);

    Note that, it is not permitted to be scannable and connectable at the same time. Therefore, the connectability mode is changed from le_gap_undirected_connectable to le_gap_connectable_non_scannable.

    To see the effect of extended advertising only, comment out the commands that are used to start the legacy advertisements: bcnSetupAdvBeaconing();, gecko_cmd_le_gap_start_advertising(HANDLE_DEMO, le_gap_general_discoverable, le_gap_undirected_connectable), and gecko_cmd_le_gap_start_advertising(HANDLE_EDDYSTONE,le_gap_user_data, le_gap_non_connectable);. Build and flash it to the target device.

  3. Now, let's modify the client to look for this advertisement and print out the name. Add the following code to the end of the if block you added in Section Getting Started with Extended Advertisements, just below the comment /*LAB TASK EXTENDED ADVT: Long Advertising Packet and the 2Mbps PHY */.

    for(int index=0;index<evt->data.evt_le_gap_extended_scan_response.data.len;)
    { /* find start of device name */
        if(evt->data.evt_le_gap_extended_scan_response.data.data[index+1] == 8|| evt->data.evt_le_gap_extended_scan_response.data.data[index+1] == 9){
                uint8 adv_name[35];
                printLog("adv packet size %d\r\n", evt->data.evt_le_gap_extended_scan_response.data.len);
                printLog("device name: ");
                snprintf(adv_name, evt->data.evt_le_gap_extended_scan_response.data.data[index],
                "%s",  &evt->data.evt_le_gap_extended_scan_response.data.data[index+2]);
                printLog("%s\r\n",adv_name);
                    if(127 == evt->data.evt_le_gap_extended_scan_response.tx_power){
                     printLog("advertised tx power is : unavailable\r\n");
                    }  else {
                            printLog("advertised tx power is : %d and RSSI is %d\r\n",
                                evt->data.evt_le_gap_extended_scan_response.tx_power,
                                evt->data.evt_le_gap_extended_scan_response.rssi);
                            }
    break;
        }
    
        else{
             index += evt->data.evt_le_gap_extended_scan_response.data.data[index]+1;
        }
    }
  4. Build the client application and flash to the target as before.

  5. Observe in the client’s console that the client now reports the server’s TX power as well as the RSSI of the advertisement.

  6. To see the effects of the advertising PHY being used switch to the Energy Profiler perspective.

In the Energy Profiler, click the Quick Access menu -> Start capture then select your server device as shown below and click OK.

  1. Let the energy capture run for a few seconds then use the slider in the bottom right corner of the screen to adjust the timebase to 20 ms so that you can see only 2 advertisements. Note the average current. (Hint: set DEBUG_LEVEL of the server to 0 in app.h, it may also be necessary to power cycle the WSTK to get the results shown below)

  2. Stop the energy capture using the Quickstart menu and Switch back to the SimplicityIDE perspective. Change the PHY used for the secondary advertisement to the 125k coded PHY as follows:

    gecko_cmd_le_gap_set_advertise_phy(HANDLE_EXTENDED,le_gap_phy_coded, le_gap_phy_coded);

    Rebuild and flash to the target board again and switch to the energy profiler and start capture as before. Adjust the timebase as in the previous step and note the new average current. You should see the average current go up significantly in the second measurement.

Anonymous Advertising

This section explains anonymous advertising, which is a new feature in Bluetooth 5 that allows an advertisement to omit the device address. Anonymous advertising is only available in extended advertisements. To make the extended advertisement anonymous, open the server application and follow the following steps.

  1. Set configuration gecko_cmd_le_gap_set_advertise_configuration(HANDLE_EXTENDED,0x02) before the call to gecko_cmd_le_gap_start_advertising(). This sets the anonymous advertising flag.

  2. Build the project and download to the target as before.

On the client side:

  1. Open app-client.c and add the following below the comment /* LAB TASK ANONYMOUS ADVERTISEMENT: check and verify reception of anonymous advertising */.

     if (evt->data.evt_le_gap_extended_scan_response.address_type & 0xFF) {
             int i = 0;
             printLog("Received scan request from: ");
             for (i = 0; i < 5; i++) {
               printLog("%02x:", evt->data.evt_le_gap_extended_scan_response.address.addr[5 - i]);
             }
             printLog("%02x\r\n", evt->data.evt_le_gap_extended_scan_response.address.addr[0]);
     }
  2. Build the project and flash it to the target client device.

  3. Open the console and you’ll see that the client reports the address as 00:00:00:00:00:00. Note: If you set the primary advertising channels as le_gap_phy_coded on the server side, remember to press PB0 to start scanning in Coded PHY (125K) on the client side.

This is a simple feature and it completes the lab portion of the training exercise.

Periodic Advertising

Periodic advertising is one of the features of Bluetooth 5's extended advertising which allows the advertiser and one or multiple scanners to sync with each other and wake up at the same time.

In this section a simple periodic advertising application that syncs a counter value is implemented. The counter value is incremented every second, which is triggered by a soft-timer.

On the server side:

  1. Open the visual GATT editor by double clicking project’s .isc file.

  2. Create a new service by clicking on the Create new item icon in upper right of configurator. Select New Service.

  3. Under General settings, set the Name of the service to periodicSync.

  4. Give it the following UUID: 2e7f05cd-df04-4e03-892b-9a4612c79bbe.

This is an important step because the client will look for a server advertising a service with this custom UUID.

  1. Check the Advertise service box.

  2. Create a characteristic for the new service by clicking on the Create new item icon and selecting New Characteristic.

  3. Under General settings, set the Name of the characteristic to testCounter.

  4. Under General settings, check the User description box and add the text "this is just a placeholder" in the space.

  5. Under Properties, set the information to only include Read with Requirement = Optional and State = True.

  6. Save the GATT configurator and click Generate to update changes to the GATT files.

  7. Open app-server.c and initialize periodic advertising feature. Add the following line of code below the comment /* LAB TASK PERIODIC ADVT: initialize periodic advertisement */.

    gecko_init_periodic_advertising();
  8. Define an array for periodic advertisement data, below the comment /* LAB TASK PERIODIC ADVT: initialize periodic advertisement data */.

    static uint16 counter = 0;
    static periodicData myCounter = {
        .length = (uint8)5,
        .type = (uint8)0xFF,
        .manuf_HI = (uint8)0xFF,
        .manuf_LO = (uint8)0xFF,
        .counter_LO = (uint8)0,
        .counter_HI = (uint8)0 };
    periodicData *pData = &myCounter;
  9. Make the following changes to the demo advertising set (i.e., HANDLE_DEMO). Note that the stack will automatically select extended advertising PDUs if periodic advertising is enabled.

    case gecko_evt_system_boot_id:
        gecko_cmd_system_set_tx_power(100);
        gecko_cmd_le_gap_set_advertise_tx_power(HANDLE_DEMO,30);
    
        gecko_cmd_le_gap_set_advertise_timing(HANDLE_DEMO, 160, 160, 0, 0);
        gecko_cmd_le_gap_clear_advertise_configuration(HANDLE_DEMO,1);
        gecko_cmd_le_gap_start_advertising(HANDLE_DEMO,le_gap_general_discoverable, le_gap_non_connectable);
        gecko_cmd_le_gap_start_periodic_advertising(HANDLE_DEMO,160,160,1);
    
        /* LAB TASK PERIODIC ADVT: set advertising data and soft timer */
    
    break;
  10. Set advertising data and soft timer that will fire every second. Add the following code below the comment /* LAB TASK PERIODIC ADVT: set advertising data and soft timer */.

    gecko_cmd_le_gap_bt5_set_adv_data(HANDLE_DEMO, 8, sizeof(periodicData), (const uint8 *)pData);
    printLog("\r\n Counter: %d \r\n", counter);
    gecko_cmd_hardware_set_soft_timer(32768, 0, 0);
  11. Create an event handler for the expired timer, increment the counter, and reset the periodic advertising data.

    case gecko_evt_hardware_soft_timer_id:
        counter++;
        pData->counter_HI = (uint8) (counter >> 8);
        pData->counter_LO = (uint8) (counter & 0xFF);
    
        //Reset the advertising data pointers to reflect the change in data
        gecko_cmd_le_gap_bt5_set_adv_data(0, 8, sizeof(periodicData), (const uint8 *)pData);
        printLog("\r\n Counter: %d \r\n", counter);
    break;

Build your project and flash it to the target device.

Open app-client.c and make the following changes.

  1. Declare the UUID of the periodic advertisement service just below the /* LAB TASK PERIODIC ADVT: periodic advertising service UUID*/ comment.

    static const uint8 periodic_sync_uuid[16] = {0xbe,0x9b,0xc7,0x12,0x46,0x9a,0x2b,0x89,0x03,0x4e,0x04,0xdf,0xcd,0x05,0x7f,0x2e};
  2. Configure the maximum number of synchronizations the Bluetooth stack needs to support. Add the following code just before the gecko initialization, below the comment /* LAB TASK PERIODIC ADVT: Set the maximum number of periodic sync allowed */

    pconfig->bluetooth.max_periodic_sync = 1;
  3. Enable periodic advertisement synchronization in the Bluetooth stack by calling the following function next to gecko_init(), just after the comment /* LAB TASK PERIODIC ADVT: initialize periodic sync feature */.

     gecko_bgapi_class_sync_init();
  4. Replace the the system boot event handler with the following code to start scanning.

     case gecko_evt_system_boot_id:
         printLog("BT5 CLIENT STARTED\r\n");
         printLog("Start scanning on %s PHY\r\n", getPhyName(scanning_phy).string);
         gecko_cmd_le_gap_set_discovery_timing(le_gap_phy_1m|le_gap_phy_coded,200,200);
         gecko_cmd_le_gap_set_discovery_type(le_gap_phy_1m|le_gap_phy_coded,0);
         gecko_cmd_le_gap_start_discovery(scanning_phy,le_gap_discover_observation);
         gecko_cmd_le_gap_set_discovery_extended_scan_response(true);
     break;
  5. Replace the event handler for extended scan responses with the following code.

     case gecko_evt_le_gap_extended_scan_response_id:
       {
         /* Only look at extended advertisements */
         if ((evt->data.evt_le_gap_extended_scan_response.packet_type & 0x80)!= 0x80)
           break;
    
         // Exit if sync is already opened for our service
         if (syncOpened)
           break;
    
         // If it is extended advertisement and sync is not opened, check if the service match
         if (serviceMatch(evt->data.evt_le_gap_extended_scan_response.data.data, evt->data.evt_le_gap_extended_scan_response.data.len)) {
           printLog("Found the periodic service. Attempting to open sync ...\r\n");
    
           uint16 skip = 1, timeout = 20;
    
           // Open sync
           syncOpenResponse = gecko_cmd_sync_open(evt->data.evt_le_gap_extended_scan_response.adv_sid, skip, timeout, evt->data.evt_le_gap_extended_scan_response.address,
               evt->data.evt_le_gap_extended_scan_response.address_type);
           if (!syncOpenResponse->result) {
             sync_handle = syncOpenResponse->sync;
             printLog("\r\n SYNC HANDLE: %d\r\n", sync_handle);
           }
    
         }
       }
     break;
  6. Create an event handler for sync open event.

     case gecko_evt_sync_opened_id:
     printLog("evt_sync_opened\r\n");
    
         /* LAB TASK PERIODIC ADVT: stop scanning */
     break;
  7. Stop scanning to save energy by ending the gap procedure. Add the following code below the comment /* LAB TASK PERIODIC ADVT: stop scanning */.

     if(evt->data.evt_sync_opened.sync == sync_handle)
         {
           syncOpened = true;
           gecko_cmd_le_gap_end_procedure();
         }
  8. Create an event handler for sync data read from the server.

    case gecko_evt_sync_data_id:
    if(evt->data.evt_sync_data.sync == sync_handle){
        printLog("\r\n Sync handle: %d\r\n", evt->data.evt_sync_data.sync);
    
        counter = (evt->data.evt_sync_data.data.data[5] << 8) + evt->data.evt_sync_data.data.data[4];
    
        printLog("\r Counter value: %d\r\n", counter);
    
        printLog("periodic sync RSSI %d and Tx power %d\r\n",
                   evt->data.evt_sync_data.rssi,
                   evt->data.evt_sync_data.tx_power);
        printLog("periodic data status %d\r\n", evt->data.evt_sync_data.data_status);
        }
    break;
  9. Create an event handler for a closed sync event.

    case gecko_evt_sync_closed_id:
        // Check if the sync handle is our service ID
        if (evt->data.evt_sync_closed.sync == sync_handle) {
          printLog(" Periodic sync closed. reason 0x%2X, sync handle %d", evt->data.evt_sync_closed.reason, evt->data.evt_sync_closed.sync);
          syncOpened = false;
        }
        /* restart discovery */
        gecko_cmd_le_gap_start_discovery(scanning_phy, le_gap_discover_observation);
    
    break;

Build the project and flash it to the targeted client device. Open the console on both devices and verify the counter value on the server being reflected on the client.

Disable the debug messages for the client in app.h by setting DEBUG_LEVEL to 0. Build the project and flash it to the device. Open the Energy Profile perspective in Simplicity Studio. Go to Quick access and Start Energy Capture for the client device. Zoom-in on the time axis to 20 ms. After a few seconds, pause the energy capture and verify the average current reading. The value should be close to the reading shown in the figure below.

Source

app-server.c

app-client.c