Mouser PSoC 6-WiFi-BT L1 : Developer Resources

Designing low-power, cloud-connected IoT devices with PSoC® 6 MCU’s and WICED® Wi-Fi/Bluetooth

Summary

This is an index of links to all of the PSoC 6 & CYW4343W learning resources.  You can click the links to go the website or see screen captures of the resources.

  1. PSoC 6 Product Page
  2. WiFi + Bluetooth Combo Product Page
  3. PSoC 6 Documentation
  4. PSoC 6 Community
  5. Wireless Combo Community
  6. CY8CKIT-062-BT-WiFi Development Kit Product Page
  7. CY8CKIT-062-BT-WiFi Development Kit Guide
  8. PSoC 6 Datasheet
  9. CYW4343W Datasheet
  10. PSoC 6 Technical Reference Manuals
  11. PSoC 6 Application Notes
  12. WiFi + Bluetooth Combo Application Notes
  13. PSoC 6 Code Examples
  14. Video Tutorials
  15. PSoC 6 Knowledge Base
  16. Peripheral Driver Library Documentation (Doxygen)
  17. WICED Documentation

PSoC 6 Product Page

You can find the PSoC 6 Product landing page for PSoC 6 here

WiFi + Bluetooth Combo Page

PSoC 6 Documentation

On the PSoC 6 Product Landing page there is a documentation tab that has links to all of the current documentation.

PSoC 6 Community

Cypress has an active development community and forum.  It can be found here.

Wireless WiFi + Bluetooth Combo Community

CY8CKIT-062-WiFi-BT Development Kit Web Page

Every Cypress development kit has a web page that contains all of the information about it, including links to the documentation and store.  The CY8CKIT-062-WiFi-BT kit page is here.

CY8CKIT-062-WiFi-BT Development Kit Guide

You can find the development kit guide here.

 

PSoC 6 Datasheet

The PSoC 6 Datasheet is available on Cypress.com here.

 

CYW4343W Datasheet

The CYW4343W datasheet can be found here.

PSoC 6 Technical Reference Manual

Each of the PSoC 6 devices has a lengthy discussion of the Technical Resources.  These documents can be found here

PSoC 6 Application Notes

You can get them all on our website… here is a link to the filtered list of PSoC 6 Application Notes.

The best application note is always the “Getting Started”.  In this case it is AN210781 “Getting Started with PSoC 6 MCU with Bluetooth Low Energy (BLE) Connectivity”

WiFi + Bluetooth Combo Application Notes

Here is a link to all of the WiFI Bluetooth Combo Application Notes.

PSoC 6 Code Examples

You can find all of the PSoC 6 code examples on the web.  In addition they are built into PSoC Creator.

Or in PSoC Creator:

Videos

Cypress has made a bunch of videos that take you step by step through an introduction to PSoC 6.  You can find them on the Cypress training website.

PSoC 6 Knowledge Base

The Cypress technical support team writes “Knowledge Base” articles when there are repeated issues reported by customers.  You can find them here.

Peripheral Driver Library Documentation (Doxygen)

All of the APIs in the PDL are documented in a Doxygen generated HTML document.  You can get there from

  • Help -> Peripheral Driver Library (this link is live only when you have a PSoC 6 project open)
  • Right click on a component -> Open PDL Documentation

Mouser PSoC 6-WiFi-BT L0 : Designing low-power, cloud-connected IoT devices with PSoC® 6 MCU’s and WICED® Wi-Fi/Bluetooth

Summary

Hello everyone.  This is lesson 0 of a series of 9 lessons about creating applications for the Cypress CY8CKIT-062-WiFi-BLE development kit.  The marketing guys call the class “Designing low-power, cloud-connected IoT devices with PSoC® 6 MCU’s and WICED® Wi-Fi/Bluetooth” … which although a really long name, is a good description of what we are going to do.

What I will do today is take you lesson by lesson through the class and talk about how it all works and what you need to do.  When I built the class it was absolutely my goal to have every button click and line of code described.  That being said,  it is likely that I made some errors.  So, during the class you will be able to send messages to my team who will answer the questions, or ask me and Ill answer live.  If you missed the class, that’s OK, you will be able to watch it on replay.  In addition if you have a question after the live stream is over, leave a comment here and Ill answer.

I will attempt to go slowly enough for you to follow along, but if I go to fast, don’t worry you should be able to follow along with the instructions on this website.

Todays virtual workshop is going to go like this.  Every lesson will have this table in it and you will be able to click to the right place.

Designing low-power, cloud-connected IoT devices with PSoC® 6 MCU’s and WICED® Wi-Fi/Bluetooth

You will need a few things for this class:

  • CY8CKIT-062-WiFi-BT
  • WICED Studio 6.2
  • CySmart or LightBlue a BLE
  • GoBle an iOS Remote Control App
  • An Amazon AWS IoT Account
  • A WiFi Access Point connected to the Internet

CY8CKIT-062-WiFi-BT

All of the projects in this series of lesson will be built to be programmed onto a CY8CKIT-062-WiFi-BT.  You can get the development kit from Mouser.  This development kit has a bunch of cool stuff including

  • PSoC 6 – The lowest power, most secure MCU for the IoT
  • CYW4343W – A WICED WiFi Bluetooth Combo Radio
  • S25FL512SAGMFI011 – A Cypress 512Mb Quad SPI Flash
  • CCG2 – A Cypress Type C Controller to manage Power

The CY8CKIT-028-TFT a full color 320×240 TFT display with an ST7789S display controller.

Here is the whole thing together

WICED Studio 6.2

This class is build around WICED Studio 6.2, the Cypress IDE built on top of Eclipse.  WICED Studio has all of the tools, examples and SDKs to build projects for the Cypress WICED Bluetooth and WiFi products.  We support Windows, Mac and Linux and you can download it from our community website: https://community.cypress.com/community/wireless (which I hope you have done by now)

CySmart or LightBlue a BLE

CySmart is a BLE GATT Browser which you can get from the iOS App store or the Google Play store

 

 

GoBle an iOS Remote Control App

GoBle is a Robot Remote Control App which can be downloaded from the iOS App Store.

An Amazon AWS IoT Account

In order to connect Amazon AWS IoT you will need to create an Amazon AWS Account.  It is essentially free to test you simple applications (obviously there are fees if you deploy many devices)

 

GoBLE Remote Control – WICED Bluetooth Implementation

Summary

I will be teaching a video training workshop for Mouser on October 24. In the class I am going to show a bunch of Bluetooth things running on PSoC6 with WICED.  Given that Bluetooth has two sides of a connection I wanted something that people could download from the iOS App Store to interact with my PSoC6/4343W design that looked like a remote control.  And, I found a program called GoBLE which was developed by a company called DF Robot to control their robots.  Here is a screenshot from my iPhone where you can see that it has four buttons on the right, a joystick on the left and two buttons in the middle.

I watched their youtube video, and it seems great… but how does it work?  And how do I make a WICED Bluetooth project to work with it?

GoBLE Documentation

So, how does the App work to send button/joystick commands?  Well, if you press the little “i” in the App, it will take you to this screen.  You can see that it sends a variable length packet of data that tells you which buttons are being pressed and where the joystick location is in x & y.  OK… but that doesn’t really tell you what to do on the Bluetooth Peripheral side.

If you look around on the internet you will find on GitHub a place where they tell you what the BLE Services/Characteristics need to look like: (sort of).

What they appear to have meant is that the SerialPortId and Command Id Characteristic need to have the GATT properties Read, WriteWithoutResponse, Write and Notify properties and that you need the Client Characteristic Configuration Descriptor for both Characteristics.  In the WICED application (that I will show you in the next section) that I build to test the remote control, they do not appear to use the CCCD or Read properties.  In addition they only use the Serial Port Id characteristic.  In fact if you do not include that Characteristic, it will still work.  The bottom line is that you database should look like this (in WICED).

    /* Primary Service 'RobotService' */
    PRIMARY_SERVICE_UUID128 (HDLS_ROBOTSERVICE, __UUID_ROBOTSERVICE),

        /* Characteristic 'SerialPortId' */
        CHARACTERISTIC_UUID128_WRITABLE (HDLC_ROBOTSERVICE_SERIALPORTID, HDLC_ROBOTSERVICE_SERIALPORTID_VALUE,
            __UUID_ROBOTSERVICE_SERIALPORTID, LEGATTDB_CHAR_PROP_READ | LEGATTDB_CHAR_PROP_WRITE_NO_RESPONSE | LEGATTDB_CHAR_PROP_WRITE | LEGATTDB_CHAR_PROP_NOTIFY,
            LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_CMD | LEGATTDB_PERM_WRITE_REQ),

            /* Descriptor 'Client Characteristic Configuration' */
            CHAR_DESCRIPTOR_UUID16_WRITABLE (HDLD_ROBOTSERVICE_SERIALPORTID_CLIENT_CONFIGURATION,
                UUID_DESCRIPTOR_CLIENT_CHARACTERISTIC_CONFIGURATION, LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_REQ | LEGATTDB_PERM_AUTH_WRITABLE),

The good news is they do service discovery and didn’t depend on a hardcoded handle.

WICED 20719 Implementation

Start by using the Bluetooth Designer to make a new project for the 20719-B1, which I will run on a CYW920719Q40EVB_01.

Click on the add Service button.

Add a Service Name as GoBLE, and then type in the UUID for the service, 0000dfb0-0000-1000-8000-00805f9b34fb.  Notice that you need to do UUIDs as little endian.

The next step is to add a characteristic.

Name the Characteristic SerialPortId and setup the UUID  0000dfb1-0000-1000-8000-00805f9b34fb (once again little endian)

Now you need to configure the Characteristic properties to match the specification.

After all that is done, press the generate code button to build the project.  Now you will need to edit a little bit of code.  Start by enabling the PUART.

#if ((defined WICED_BT_TRACE_ENABLE) || (defined HCI_TRACE_OVER_TRANSPORT))
    /* Set the Debug UART as WICED_ROUTE_DEBUG_NONE to get rid of prints */
    //  wiced_set_debug_uart( WICED_ROUTE_DEBUG_NONE );

    /* Set Debug UART as WICED_ROUTE_DEBUG_TO_PUART to see debug traces on Peripheral UART (PUART) */
      wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_PUART );

    /* Set the Debug UART as WICED_ROUTE_DEBUG_TO_WICED_UART to send debug strings over the WICED debug interface */
    //wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_WICED_UART );
#endif

The iPhone App recognizes you as a peripheral by seeing the Service UUID advertised.  Unfortunately whoever wrote the advertising packet parser assumed that the Service UUID was first (which it doesn’t have to be).  If you notice I added the name of the device to the advertising packet… but while I was trying to figure that out I put a #if 1 / #endif around that part of the packet.  (notice that on line 178 I modified it the number of packet elements to be 3.

/* Set Advertisement Data */
void gobletest_set_advertisement_data( void )
{
    wiced_bt_ble_advert_elem_t adv_elem[3] = { 0 };
    uint8_t adv_flag = BTM_BLE_GENERAL_DISCOVERABLE_FLAG | BTM_BLE_BREDR_NOT_SUPPORTED;
    uint8_t num_elem = 0; 

    /* Advertisement Element for Flags */
    adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_FLAG;
    adv_elem[num_elem].len = sizeof(uint8_t);
    adv_elem[num_elem].p_data = &adv_flag;
    num_elem++;

    uint8_t gobleuuid[] = {__UUID_GOBLE};

    /* Advertisement Element for Name */
    adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_128SRV_COMPLETE;
    adv_elem[num_elem].len = 16;
    adv_elem[num_elem].p_data = gobleuuid;
    num_elem++;

#if 1

    /* Advertisement Element for Name */
    adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_NAME_COMPLETE;
    adv_elem[num_elem].len = strlen((const char*)BT_LOCAL_NAME);
    adv_elem[num_elem].p_data = BT_LOCAL_NAME;
    num_elem++;
#endif
    /* Set Raw Advertisement Data */
    wiced_bt_ble_set_raw_advertisement_data(num_elem, adv_elem);
}

When the App writes to the 20719 you will get a callback in the function “goble_server_callback”.  To figure it out I print out the raw data, as well as the parsed version.

/* GATT Server Event Callback */
wiced_bt_gatt_status_t gobletest_server_callback( uint16_t conn_id, wiced_bt_gatt_request_type_t type, wiced_bt_gatt_request_data_t *p_data )
{
    wiced_bt_gatt_status_t status = WICED_BT_GATT_ERROR;

    switch ( type )
    {
    case GATTS_REQ_TYPE_READ:
        status = gobletest_read_handler( &p_data->read_req, conn_id );
        break;
    case GATTS_REQ_TYPE_WRITE:
        if(p_data->write_req.handle == HDLC_GOBLE_SERIALPORTID_VALUE)
        {
            WICED_BT_TRACE("Activate = ");
            for(int i=0;i<p_data->write_req.val_len;i++)
            {
                WICED_BT_TRACE("%02X ",p_data->write_req.p_val[i]);
            }
            WICED_BT_TRACE("\n");
            uint32_t numButtons = p_data->write_req.p_val[3];
            uint32_t sliderX = p_data->write_req.p_val[5+numButtons];
            uint32_t sliderY = p_data->write_req.p_val[6+numButtons];
            uint32_t buttonMask = 0x00;
            for(int i=0;i<numButtons;i++)
            {
                buttonMask |= (1<<p_data->write_req.p_val[5+i]);
            }

            WICED_BT_TRACE("# Buttons = %d ButtonMask=%X Slider x=%X Slider Y=%X\n",numButtons,buttonMask,sliderX,sliderY);
            status = WICED_BT_GATT_SUCCESS;
        }
        else
            status = gobletest_write_handler( &p_data->write_req, conn_id );
        break;
    }

    return status;
}

In the file wiced_bt_cfg.c modify the advertising duration to “0” which means never timeout.

   /* BLE Advertisement Settings */
    .ble_advert_cfg = {
        .channel_map =                      BTM_BLE_ADVERT_CHNL_37 |                                    /**< Advertising Channel Map (mask of BTM_BLE_ADVERT_CHNL_37, BTM_BLE_ADVERT_CHNL_38, BTM_BLE_ADVERT_CHNL_39) */
                                            BTM_BLE_ADVERT_CHNL_38 |
                                            BTM_BLE_ADVERT_CHNL_39,

        .high_duty_min_interval =           WICED_BT_CFG_DEFAULT_HIGH_DUTY_ADV_MIN_INTERVAL,            /**< High Duty Undirected Connectable Minimum Advertising Interval */
        .high_duty_max_interval =           WICED_BT_CFG_DEFAULT_HIGH_DUTY_ADV_MAX_INTERVAL,            /**< High Duty Undirected Connectable Maximum Advertising Interval */
        .high_duty_duration =               0,                                                         /**< High Duty Undirected Connectable Advertising Duration in seconds (0 for infinite) */

Now that is all done I can program the development kit.  The phone immediately recognizes the kit.  And, when I press the buttons you can see that they are printed out.  You can see that I pressed two buttons at a time to start, then I moved the slider around.

OK.  All good.

 

Mouser Video Training Workshop – October 24

On October 24, I will be teaching a Mouser video training workshop … live streaming on the internet.  The workshop will be about PSoC, WICED, WiFi and Bluetooth.  I am going to show PSoC Creator, WICED Studio and Cypress’s new development tool Modus Toolbox.

You can register for the workshop at this link.

I am going to build the whole class around the CY8CKIT-062-BLE-WiFi Development Kit.  You can get the devlopment kit from Mouser.

Here is the introduction:

 

 

WICED 20719 BLE Central Custom Profile w/LED & CapSense – Part 2

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 

WICED 20719 BLE Central Custom Profile w/LED & CapSense – Part 1

Summary

Last year I posted an article about making a BLE Central using PSoC 4 BLE.  Recently, I got a comment from a reader who was interested in the source code to the PSoC 4 BLE project which made me think of BLE Centrals again, especially because in the last several months I have spent a significant amount of time writing a book about WICED BLE.  Given all that, it only made sense to create a WICED BLE Central that mimics the PSoC Central from the original article.

In the original article I made a connection to a PSoC4 BLE that was acting as a Peripheral with a Vendor Specific Service which I called “ledcapsense”.  Then Central could then turn on/off an LED, and get notifications when the CapSense changed.  In this series of articles I will make a connection to that same PSoC 4 BLE device, except that I will use a WICED CYW920719Q40EVB_01.

CYW920719Q40EVB_01 20719

I will breakup this article into three parts

  1. Find the Peripheral, make a connection, write the GATT database to set the LED to 0 & 1
  2. Add the ability set the the CCCD for the CapSense Characteristic
  3. Perform Service Discovery

This first article will be broken up into the following steps

  1. Make a New Project Using Bluetooth Designer
  2. Remove all of the unused Advertising Code
  3. Add a PUART Command Line Handler
  4. Make the Central Scan for Peripheral Devices
  5. Make the Connection & Disconnect
  6. Write the LED Characteristic

Make a New Project Using Bluetooth Designer

It is easiest to let the Bluetooth Designer create a template project for me.  To do this, pick WICED Bluetooth Designer from the File->New menu.

PSoC Creator BLE Customizer

Give a project name of ex01ScanConnect and choose the 20719-B1

WICED Studio

Turn off the GATT database and then press Generate Code

WICED Studio Bluetooth Designer

This will make a project in the top level Apps folder, but I want i to be in the WICED_Central directory, so cut and paste it.

WICED Studio Bluetooth Designer

Now it looks like this:

WICED Studio Bluetooth Designer

I want to make sure the project will build, so Ill set the debug traces to go to the the PUART

#if ((defined WICED_BT_TRACE_ENABLE) || (defined HCI_TRACE_OVER_TRANSPORT))
    /* Set the Debug UART as WICED_ROUTE_DEBUG_NONE to get rid of prints */
    //  wiced_set_debug_uart( WICED_ROUTE_DEBUG_NONE );

    /* Set Debug UART as WICED_ROUTE_DEBUG_TO_PUART to see debug traces on Peripheral UART (PUART) */
      wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_PUART );

    /* Set the Debug UART as WICED_ROUTE_DEBUG_TO_WICED_UART to send debug strings over the WICED debug interface */
    //wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_WICED_UART );
#endif

Then I create a make target for the project

WICED Studio Make Target

Next, lets make sure that it works.

WICED Studio

Everything seems OK… although it is advertising, which I don’t want to do.  But that is easy enough to fix.

WICED 20719 Test

Remove all of the Advertising code

Lets get rid of all of the advertising code.  First Ill remove the function prototypes for “…_set_advertisement_data” and “…_advertisement_stopped”

/*******************************************************************
 * Function Prototypes
 ******************************************************************/
static void                  ex01scanconnect_app_init               ( void );
static wiced_bt_dev_status_t ex01scanconnect_management_callback    ( wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data );
static void                  ex01scanconnect_set_advertisement_data ( void );
static void                  ex01scanconnect_advertisement_stopped  ( void );
static void                  ex01scanconnect_reset_device           ( void );
static uint32_t              hci_control_process_rx_cmd             ( uint8_t* p_data, uint32_t len );
#ifdef HCI_TRACE_OVER_TRANSPORT
static void                  ex01scanconnect_trace_callback         ( wiced_bt_hci_trace_type_t type, uint16_t length, uint8_t* p_data );
#endif

Then Ill delete everything from “…set_pairable_mode” on line 128 down through the two functions ending on line 169

    /* Allow peer to pair */
    wiced_bt_set_pairable_mode(WICED_TRUE, 0);

    /* Set Advertisement Data */
    ex01scanconnect_set_advertisement_data();

    /* Start Undirected LE Advertisements on device startup.
     * The corresponding parameters are contained in 'wiced_bt_cfg.c' */
    /* TODO: Make sure that this is the desired behavior. */
    wiced_bt_start_advertisements(BTM_BLE_ADVERT_UNDIRECTED_HIGH, 0, NULL);
}

/* Set Advertisement Data */
void ex01scanconnect_set_advertisement_data( void )
{
    wiced_bt_ble_advert_elem_t adv_elem[2] = { 0 };
    uint8_t adv_flag = BTM_BLE_GENERAL_DISCOVERABLE_FLAG | BTM_BLE_BREDR_NOT_SUPPORTED;
    uint8_t num_elem = 0; 

    /* Advertisement Element for Flags */
    adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_FLAG;
    adv_elem[num_elem].len = sizeof(uint8_t);
    adv_elem[num_elem].p_data = &adv_flag;
    num_elem++;

    /* Advertisement Element for Name */
    adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_NAME_COMPLETE;
    adv_elem[num_elem].len = strlen((const char*)BT_LOCAL_NAME);
    adv_elem[num_elem].p_data = BT_LOCAL_NAME;
    num_elem++;

    /* Set Raw Advertisement Data */
    wiced_bt_ble_set_raw_advertisement_data(num_elem, adv_elem);
}

/* This function is invoked when advertisements stop */
void ex01scanconnect_advertisement_stopped( void )
{
    WICED_BT_TRACE("Advertisement stopped\n");

    /* TODO: Handle when advertisements stop */
}

In the Bluetooth Management Callback function you dont need the local variable p_adv_mode (line 145) so delete it.

/* Bluetooth Management Event Handler */
wiced_bt_dev_status_t ex01scanconnect_management_callback( wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data )
{
    wiced_bt_dev_status_t status = WICED_BT_SUCCESS;
    wiced_bt_device_address_t bda = { 0 };
    wiced_bt_dev_ble_pairing_info_t *p_ble_info = NULL;
    wiced_bt_ble_advert_mode_t *p_adv_mode = NULL;

And, because you are not advertising, you don’t need to handle that callback so delete this block of code.

    case BTM_BLE_ADVERT_STATE_CHANGED_EVT:
        /* Advertisement State Changed */
        p_adv_mode = &p_event_data->ble_advert_state_changed;
        WICED_BT_TRACE("Advertisement State Change: %d\n", *p_adv_mode);
        if ( BTM_BLE_ADVERT_OFF == *p_adv_mode )
        {
            ex01scanconnect_advertisement_stopped();
        }
        break;

Now run the make target again to make sure you didn’t break anything.

After programming, things still seem to work.

WICED 20719 Test

Add PUART Command Line Handler

In this project I am going to make keyboard commands to do the different things.  In order to make all of that work, Ill include the HAL for the PUART.

#include "wiced_hal_puart.h"

Then Ill add a function prototype for the callback for the receive data handler (line 59)

/*******************************************************************
 * Function Prototypes
 ******************************************************************/
static void                  ex01scanconnect_app_init               ( void );
static wiced_bt_dev_status_t ex01scanconnect_management_callback    ( wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data );
static uint32_t              hci_control_process_rx_cmd             ( uint8_t* p_data, uint32_t len );
#ifdef HCI_TRACE_OVER_TRANSPORT
static void                  ex01scanconnect_trace_callback         ( wiced_bt_hci_trace_type_t type, uint16_t length, uint8_t* p_data );
#endif

static void rx_cback( void *data )

In the application init function Ill initialize the PUART and setup a callback for keys from the serial port.

void ex01scanconnect_app_init(void)
{
    /* Initialize Application */
    wiced_bt_app_init();
    
    /* Initialize the UART for input */
     wiced_hal_puart_init( );
     wiced_hal_puart_flow_off( );
     wiced_hal_puart_set_baudrate( 115200 );
     /* Enable receive and the interrupt */
     wiced_hal_puart_register_interrupt( rx_cback );
     /* Set watermark level to 1 to receive interrupt up on receiving each byte */
     wiced_hal_puart_set_watermark_level( 1 );
     wiced_hal_puart_enable_rx();
}

And create a new function called “rx_cback” which will be called when a key is pressed.  In this case the only key to process is ‘?’ which will print out the help.

void rx_cback( void *data )
{
    uint8_t  readbyte;
    uint32_t focus;

    /* Read one byte from the buffer and (unlike GPIO) reset the interrupt */
    wiced_hal_puart_read( &readbyte );
    wiced_hal_puart_reset_puart_interrupt();

    switch (readbyte)
    {


    case '?':
        /* Print help */
        WICED_BT_TRACE( "\n" );
        WICED_BT_TRACE( "+------- Available Commands -------+\n" );
        WICED_BT_TRACE( "|  ?    Print Commands             |\n" );
        WICED_BT_TRACE( "+----------------------------------+\n" );
        WICED_BT_TRACE( "\n" );
        break;
    }
}

Program it again and make sure that the ‘?’ works

WICED 20719 Test

Make the Central Scan for Peripheral Devices

You might recall that the PSoC 4 CapSense BLE Peripheral is advertising a “Service UUID” that is my custom service.  Here is a picture of the advertising packet customizer from PSoC Creator.

PSoC Creator Component Customizer

If you look in the PSoC Creator project in the Generated Source file ble_gatt.c you will find C-Declarations of the UUIDs for the ledcapsense service, the led characteristic and the capsense characteristic.

const uint8 cyBle_attUuid128[][16u] = {
    /* ledcapsense */
    { 0xF0u, 0x34u, 0x9Bu, 0x5Fu, 0x80u, 0x00u, 0x00u, 0x80u, 0x00u, 0x10u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u },
    /* led */
    { 0xF1u, 0x34u, 0x9Bu, 0x5Fu, 0x80u, 0x00u, 0x00u, 0x80u, 0x00u, 0x10u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u },
    /* capsense */
    { 0xF2u, 0x34u, 0x9Bu, 0x5Fu, 0x80u, 0x00u, 0x00u, 0x80u, 0x00u, 0x10u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u },
};

I copy that byte array for ledcapsense into my project so that I can match against it.

static const uint8_t matchServiceUUID[] = {0xF0 ,0x34 ,0x9B ,0x5F ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 };

The way that the WICED scanner works is that it will give you a callback every time it hears a Peripheral advertisement packet.  It passes you the pointer to some information about what device it heard (p_scan_result), as well as the raw bytes of the advertising packet (p_adv_data).  WICED has a function called “wiced_bt_ble_check_advertising_data” which will search through the raw advertising data looking for a field of the type you specify.  If found, the function will return a pointer to the raw data.  In this case I’m looking for a field of type “BTM_BLE_ADVERT_TYPE_128SRV_COMPLETE”, in other words, a device that is advertising that it has a 128-uuid service as available on that device.

All this function does is, if I find that field in the advertising packet and the service UUID matches the capsenseled UUID, then I print out that I found it.

// This function is called when an advertising packet is received.
void newAdvCallback(wiced_bt_ble_scan_results_t *p_scan_result, uint8_t *p_adv_data)
{

    uint8_t length;

    uint8_t *serviceUUID = wiced_bt_ble_check_advertising_data(p_adv_data,BTM_BLE_ADVERT_TYPE_128SRV_COMPLETE,&length);
    if(serviceUUID && memcmp(serviceUUID,matchServiceUUID,16) == 0)
    {
        WICED_BT_TRACE("Host = %B Found Service UUID\r\n ",p_scan_result->remote_bd_addr);

    }

}

At the bottom of the project, Ill add ‘s’ to start scanning and ‘S’ to stop scanning.

    switch (readbyte)
    {

    case 's':
        WICED_BT_TRACE( "Scan On\r\n" );
        wiced_bt_ble_scan(BTM_BLE_SCAN_TYPE_HIGH_DUTY,FALSE,newAdvCallback);
        break;
    case 'S':
        WICED_BT_TRACE( "Scan Off\r\n" );
        wiced_bt_ble_scan(BTM_BLE_SCAN_TYPE_NONE,FALSE,newAdvCallback);
        break;

And don’t forget to update the help.

        WICED_BT_TRACE( "|  s    Turn on Scanning           |\n" );
        WICED_BT_TRACE( "|  S    Turn off Scanning          |\n" );

When I run the make target everything appears to be working.  First I press ‘?’ and the help is correct.  Then I press ‘s’ to start scanning.  It immediately (and repeatedly) finds my device.

WICED 20719 Test

What is the unhandled Bluetooth Management Event: 0x16 (22)?  You can find the answer to that question by right clicking on the wiced_bt_management_event_t and “Open Declaration”

WICED Studio

That will take you to the “wiced_bt_dev.h” file in this enumeration.  On line 683 you will see the “BTM_BLE_SCAN_STATE_CHANGED_EVT” which you are getting a callback every time the scan state changes.

enum wiced_bt_management_evt_e {
    /* Bluetooth status events */
    BTM_ENABLED_EVT,                                /**< Bluetooth controller and host stack enabled. Event data: wiced_bt_dev_enabled_t */
    BTM_DISABLED_EVT,                               /**< Bluetooth controller and host stack disabled. Event data: NULL */
    BTM_POWER_MANAGEMENT_STATUS_EVT,                /**< Power management status change. Event data: wiced_bt_power_mgmt_notification_t */
#ifdef WICED_X
    BTM_RE_START_EVT,                             /**< Bluetooth controller and host stack re-enabled. Event data: tBTM_ENABLED_EVT */
#endif
    /* Security events */
    BTM_PIN_REQUEST_EVT,                            /**< PIN request (used only with legacy devices). Event data: #wiced_bt_dev_name_and_class_t */
    BTM_USER_CONFIRMATION_REQUEST_EVT,              /**< received USER_CONFIRMATION_REQUEST event (respond using #wiced_bt_dev_confirm_req_reply). Event data: #wiced_bt_dev_user_cfm_req_t */
    BTM_PASSKEY_NOTIFICATION_EVT,                   /**< received USER_PASSKEY_NOTIFY event. Event data: #wiced_bt_dev_user_key_notif_t */
    BTM_PASSKEY_REQUEST_EVT,                        /**< received USER_PASSKEY_REQUEST event (respond using #wiced_bt_dev_pass_key_req_reply). Event data: #wiced_bt_dev_user_key_req_t */
    BTM_KEYPRESS_NOTIFICATION_EVT,                  /**< received KEYPRESS_NOTIFY event. Event data: #wiced_bt_dev_user_keypress_t */
    BTM_PAIRING_IO_CAPABILITIES_BR_EDR_REQUEST_EVT, /**< Requesting IO capabilities for BR/EDR pairing. Event data: #wiced_bt_dev_bredr_io_caps_req_t */
    BTM_PAIRING_IO_CAPABILITIES_BR_EDR_RESPONSE_EVT,/**< Received IO capabilities response for BR/EDR pairing. Event data: #wiced_bt_dev_bredr_io_caps_rsp_t */
    BTM_PAIRING_IO_CAPABILITIES_BLE_REQUEST_EVT,    /**< Requesting IO capabilities for BLE pairing. Slave can check peer io capabilities in event data before updating with local io capabilities. Event data: #wiced_bt_dev_ble_io_caps_req_t */
    BTM_PAIRING_COMPLETE_EVT,                       /**< received SIMPLE_PAIRING_COMPLETE event. Event data: #wiced_bt_dev_pairing_cplt_t */
    BTM_ENCRYPTION_STATUS_EVT,                      /**< Encryption status change. Event data: #wiced_bt_dev_encryption_status_t */
    BTM_SECURITY_REQUEST_EVT,                       /**< Security request (respond using #wiced_bt_ble_security_grant). Event data: #wiced_bt_dev_security_request_t */
    BTM_SECURITY_FAILED_EVT,                        /**< Security procedure/authentication failed. Event data: #wiced_bt_dev_security_failed_t */
    BTM_SECURITY_ABORTED_EVT,                       /**< Security procedure aborted locally, or unexpected link drop. Event data: #wiced_bt_dev_name_and_class_t */

    BTM_READ_LOCAL_OOB_DATA_COMPLETE_EVT,           /**< Result of reading local OOB data (wiced_bt_dev_read_local_oob_data). Event data: #wiced_bt_dev_local_oob_t */
    BTM_REMOTE_OOB_DATA_REQUEST_EVT,                /**< OOB data from remote device (respond using #wiced_bt_dev_remote_oob_data_reply). Event data: #wiced_bt_dev_remote_oob_t */

    BTM_PAIRED_DEVICE_LINK_KEYS_UPDATE_EVT,         /**< Updated remote device link keys (store device_link_keys to  NV memory). This is the place to 
verify that the correct link key has been generated. Event data: #wiced_bt_device_link_keys_t */
    BTM_PAIRED_DEVICE_LINK_KEYS_REQUEST_EVT,        /**< Request for stored remote device link keys (restore device_link_keys from NV memory). If successful, return WICED_BT_SUCCESS. Event data: #wiced_bt_device_link_keys_t */

    BTM_LOCAL_IDENTITY_KEYS_UPDATE_EVT,             /**< Update local identity key (stored local_identity_keys NV memory). Event data: #wiced_bt_local_identity_keys_t */
    BTM_LOCAL_IDENTITY_KEYS_REQUEST_EVT,            /**< Request local identity key (get local_identity_keys from NV memory). If successful, return WICED_BT_SUCCESS. Event data: #wiced_bt_local_identity_keys_t */

    BTM_BLE_SCAN_STATE_CHANGED_EVT,                 /**< BLE scan state change. Event data: #wiced_bt_ble_scan_type_t */
    BTM_BLE_ADVERT_STATE_CHANGED_EVT,               /**< BLE advertisement state change. Event data: #wiced_bt_ble_advert_mode_t */

    /* BLE Secure Connection events */
    BTM_SMP_REMOTE_OOB_DATA_REQUEST_EVT,            /**< SMP remote oob data request. Reply using wiced_bt_smp_oob_data_reply. Event data: wiced_bt_smp_remote_oob_req_t  */
    BTM_SMP_SC_REMOTE_OOB_DATA_REQUEST_EVT,         /**< LE secure connection remote oob data request. Reply using wiced_bt_smp_sc_oob_reply. Event data: #wiced_bt_smp_sc_remote_oob_req_t */
    BTM_SMP_SC_LOCAL_OOB_DATA_NOTIFICATION_EVT,     /**< LE secure connection local OOB data (wiced_bt_smp_create_local_sc_oob_data). Event data: #wiced_bt_smp_sc_local_oob_t*/

    BTM_SCO_CONNECTED_EVT,                          /**< SCO connected event. Event data: #wiced_bt_sco_connected_t */
    BTM_SCO_DISCONNECTED_EVT,                       /**< SCO disconnected event. Event data: #wiced_bt_sco_disconnected_t */
    BTM_SCO_CONNECTION_REQUEST_EVT,                 /**< SCO connection request event. Event data: #wiced_bt_sco_connection_request_t */
    BTM_SCO_CONNECTION_CHANGE_EVT,					/**< SCO connection change event. Event data: #wiced_bt_sco_connection_change_t */
    BTM_BLE_CONNECTION_PARAM_UPDATE                 /**< BLE connection parameter update. Event data: #wiced_bt_ble_connection_param_update_t */

};
#endif
typedef uint8_t wiced_bt_management_evt_t;          /**< Bluetooth management events (see #wiced_bt_management_evt_e) */

You notice that the event parameter is of type “wiced_bt_ble_scan_type_t”.  When I right click, I find its definition is this:

enum wiced_bt_ble_scan_type_e
{
    BTM_BLE_SCAN_TYPE_NONE,         /**< Stop scanning */
    BTM_BLE_SCAN_TYPE_HIGH_DUTY,    /**< High duty cycle scan */
    BTM_BLE_SCAN_TYPE_LOW_DUTY      /**< Low duty cycle scan */
};

Now I can add a case to the Bluetooth Management callback to handle the case “BTM_BLE_SCAN_STATE_CHANGED_EVT”.  All it does it look at the parameter and print it out.

    case BTM_BLE_SCAN_STATE_CHANGED_EVT:
        WICED_BT_TRACE("Scan State Change: ");
        if(p_event_data->ble_scan_state_changed == BTM_BLE_SCAN_TYPE_NONE)
            WICED_BT_TRACE("BTM_BLE_SCAN_TYPE_NONE\n");
        else if (p_event_data->ble_scan_state_changed == BTM_BLE_SCAN_TYPE_HIGH_DUTY)
            WICED_BT_TRACE("BTM_BLE_SCAN_TYPE_HIGH_DUTY\n");
        else if(p_event_data->ble_scan_state_changed == BTM_BLE_SCAN_TYPE_LOW_DUTY)
            WICED_BT_TRACE("BTM_BLE_SCAN_TYPE_LOW_DUTY\n");
        else
            WICED_BT_TRACE("Unknkown\n");
        break;

OK now when I run the program and start scanning I get this.  Which makes good sense.

WICED 20719 Test

But if I run the scanning for a while, I get this.  Why does it do this transition to “BTM_BLE_SCAN_TYPE_LOW_DUTY”?

WICED 20719 Test

The answer to that question can be found on line 53 of “wiced_bt_cfg.c”.  That “5” means scan at high duty cycle for 5 seconds, then go to low duty cycle scanning for 5 more seconds then stops scanning.  This is done to save power as scanning is very current consuming.  If you want to keep scanning forever, change those values to 0 (which means stay in that mode forever)

    /* BLE Scan Settings */
    .ble_scan_cfg = {
        .scan_mode =                        BTM_BLE_SCAN_MODE_PASSIVE,                                  /**< BLE Scan Mode (BTM_BLE_SCAN_MODE_PASSIVE or BTM_BLE_SCAN_MODE_ACTIVE) */

        /* Advertisement Scan Configuration */
        .high_duty_scan_interval =          WICED_BT_CFG_DEFAULT_HIGH_DUTY_SCAN_INTERVAL,               /**< High Duty Scan Interval */
        .high_duty_scan_window =            WICED_BT_CFG_DEFAULT_HIGH_DUTY_SCAN_WINDOW,                 /**< High Duty Scan Window */
        .high_duty_scan_duration =          5,                                                          /**< High Duty Scan Duration in seconds (0 for infinite) */

        .low_duty_scan_interval =           WICED_BT_CFG_DEFAULT_LOW_DUTY_SCAN_INTERVAL,                /**< Low Duty Scan Interval */
        .low_duty_scan_window =             WICED_BT_CFG_DEFAULT_LOW_DUTY_SCAN_WINDOW,                  /**< Low Duty Scan Window */
        .low_duty_scan_duration =           5,                                                          /**< Low Duty Scan Duration in seconds (0 for infinite) */

Make the Connection

Now that I have found a device, how do I make a connection?  Simple, call wiced_bt_gatt_connect.  The other thing that you want to do is turn off the scanning by calling wiced_bt_ble_scan with “BTM_BLE_SCAN_TYPE_NONE”.

// This function is called when an advertising packet is received.
void newAdvCallback(wiced_bt_ble_scan_results_t *p_scan_result, uint8_t *p_adv_data)
{

    uint8_t length;

    uint8_t *serviceUUID = wiced_bt_ble_check_advertising_data(p_adv_data,BTM_BLE_ADVERT_TYPE_128SRV_COMPLETE,&length);
    if(serviceUUID && memcmp(serviceUUID,matchServiceUUID,16) == 0)
    {
        WICED_BT_TRACE("Host = %B Found Service UUID\n ",p_scan_result->remote_bd_addr);
        wiced_bt_gatt_le_connect(p_scan_result->remote_bd_addr,p_scan_result->ble_addr_type,BLE_CONN_MODE_HIGH_DUTY,WICED_TRUE);
        wiced_bt_ble_scan(BTM_BLE_SCAN_TYPE_NONE,FALSE,newAdvCallback);


    }

}

All of the functions that let you exchange data require a connection id.  The 20719 lets you handle multiple BLE (and Bluetooth Classic) connections and each connection will have a different connection id.  At the top of your project the easiest thing to do is create a global variable to keep track of the connection id.  Initialize it  to 0 meaning no connection.

static uint16_t conn_id=0;

You might have noticed that the connection api was “…gatt_le_connect”.   This means that while you are connected, almost all of the interaction will happen with a gatt callback which looks like this.  Add it to the function declarations at the top of your project.

static wiced_bt_gatt_status_t gatt_callback( wiced_bt_gatt_evt_t event, wiced_bt_gatt_event_data_t *p_data);

And in the application_init register your callback.

        wiced_bt_gatt_register( gatt_callback );

Now we need to actually create the callback function.  This function will just be a switch to look at what type of gatt event just happened.  We will start with the only case being the connection event.  If this event is a connection, save the connection id and print out the bd address of the peripheral.  If this is a disconnect, then set the connection id back to 0.

wiced_bt_gatt_status_t gatt_callback( wiced_bt_gatt_evt_t event, wiced_bt_gatt_event_data_t *p_data)
{
    wiced_bt_gatt_status_t result = WICED_BT_SUCCESS;

    switch( event )
    {
    case GATT_CONNECTION_STATUS_EVT:
        if ( p_data->connection_status.connected )
        {
            WICED_BT_TRACE("Connected\r\n");
            wiced_bt_gatt_connection_status_t *p_conn_status = &p_data->connection_status;
            conn_id         =  p_conn_status->conn_id;
            WICED_BT_TRACE("Connection ID=%d\r\n",conn_id);
        }
        else
        {
            WICED_BT_TRACE(("Disconnected\r\n"));
            conn_id = 0;
        }
        break;


    default:
        WICED_BT_TRACE("Unknown GATT Event %d\n",event);
        break;
    }

    return result;
}

The last thing you need to do to get the connection to work is modify wiced_bt_cfg.c and increase the .client_max_links to at least 1.

    /* GATT Configuration */
    .gatt_cfg = {
        .appearance =                       0x0000,                                                     /**< GATT Appearance */
        .client_max_links =                 1,                                                          /**< Client Config: Maximum number of servers that local client can connect to */
        .server_max_links =                 0,                                                          /**< Server Config: Maximum number of remote client connections allowed by local server */
        .max_attr_len =                     512,                                                        /**< Maximum attribute length; wiced_bt_cfg must have a corresponding buffer pool that can hold this length */
        .max_mtu_size =                     515,                                                        /**< Maximum MTU size for GATT connections, should be between 23 and (max_attr_len + 5) */
    },

We setup all of the code to make a connection.  How about the disconnect?  That is also easy.  Il add a new case the user interface ‘d’ to call wiced_bt_gatt_disconnect.

    case 'd':
        wiced_bt_gatt_disconnect(conn_id);
        break;

Now when I program and test you can see that I can make a connection (which barfs out a bunch of messages about pairing not working) and then I can disconnect.

WICED 20719 Test

Write the LED Characteristic

Finally we are ready to write the LED.  You might recall from the original peripheral project that it has a Service with two characteristics, one for an LED and one for a CapSense value.  Here is the customizer screen.

PSoC Creator BLE Customizer

You might recall that all BLE transactions take place in reference to a handle (just a 16 bit number in the Attribute Database).  But what is the handle of the LED characteristic? You can see from the PSoC Creator project in file ble_custom.c that the handle of the LED characteristic is 0x0E.  Note: this is a seriously bad way to find out the handle for a characteristic.  The correct way is to use service discovery which Ill show you in the third article.

const CYBLE_CUSTOMS_T cyBle_customs[0x01u] = {

    /* ledcapsense service */
    {
        0x000Cu, /* Handle of the ledcapsense service */ 
        {

            /* led characteristic */
            {
                0x000Eu, /* Handle of the led characteristic */ 
                
                /* Array of Descriptors handles */
                {
                    0x000Fu, /* Handle of the Characteristic User Description descriptor */ 
                    CYBLE_GATT_INVALID_ATTR_HANDLE_VALUE, 
                }, 
            },

            /* capsense characteristic */
            {
                0x0011u, /* Handle of the capsense characteristic */ 
                
                /* Array of Descriptors handles */
                {
                    0x0012u, /* Handle of the capsensecccd descriptor */ 
                    0x0013u, /* Handle of the Characteristic User Description descriptor */ 
                }, 
            },
        }, 
    },
};

In order to write the characteristic I will create a new function that will let me write a 0 or 1.  This function simply

  • Checks to make sure that there is a connection
  • Allocates a block of memory to hold the structure required to send the write
  • Sets up the structure with the handle, offset, length and value
  • Send the write
  • Frees the buffer
// writeLED is a function to send either a 1 or a 0 to the LED Characteristic
// This function will check and see if there is a connection and we know the handle of the LED
// It will then setup a write... and then write
void writeLed(uint8_t val)
{
    if(conn_id == 0)
        return;


    wiced_bt_gatt_value_t *p_write = ( wiced_bt_gatt_value_t* )wiced_bt_get_buffer( sizeof( wiced_bt_gatt_value_t ));
    if ( p_write )
        {
            p_write->handle   = 0x0E; // Hardcoded handle
            p_write->offset   = 0;
            p_write->len      = 1;
            p_write->auth_req = GATT_AUTH_REQ_NONE;
            p_write->value[0] = val;

            wiced_bt_gatt_status_t status = wiced_bt_gatt_send_write ( conn_id, GATT_WRITE, p_write );

            WICED_BT_TRACE("wiced_bt_gatt_send_write 0x%X\r\n", status);

            wiced_bt_free_buffer( p_write );
        }

}

I want to use the buffer allocation functions, so at the top of my program Ill include the wiced_memory.h header file.

#include "wiced_memory.h"

To make the writes work I just call the “writeLed” function in the keyboard handler.

    case '0':
        WICED_BT_TRACE("LED Off\r\n");
        writeLed(0);
        break;

    case '1':
        WICED_BT_TRACE("LED On\r\n");
        writeLed(1);
        break;

Now when I test, everything is working.

WICED 20719 Test

And here are the two development kits talking nice to each other (at least it works from 2 inches away 🙂 )

WICED 20719 and PSoC 4 BLE

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

IoT Mailbox: Solar Battery Chargers & System Power Supplies

Summary

In the last Article I talked about my Mailbox problem.  My original plan was to have this device powered with a coin cell.  As I discussed the project with my lab assistant, Nicholas, he asked why it wasn’t going to be solar powered.  I didn’t have a good answer for this question.  This basic question led me down a multi-week deep dark rabbit hole.  For a while (weeks?) I am going to write about my experiences building a solar power supply for my board.  Ideally I want this architecture:

In words, I want to power the system at 3.3v from a battery, USB or a solar cells.  And, I want the solar cell and/or the USB to charge the LiPo battery.  It turns out that I don’t/didn’t know much about:

  1. Solar Cells
  2. Charging LiPo batteries – or in fact batteries
  3. Buck-Boost / Buck Convertors
  4. Super Capacitors

And it turns out that there is an unbelievably large number of PMIC combinations that might work.  Unfortunately, Cypress does not make one.  We do make an Energy Harvesting Boost Convertor, but nothing that can do battery charging.  The last things that surprised me about this whole thing is that the normal maker suspects (Adafruit, SEEED Studio and Sparkfun) don’t really make good breakout boards that meet my architecture needs.

My current plan is to:

  1. Research, buy and evaluate “a bunch” of different evaluation kits from the usual suspects (Ti, Analog, Linear, ST and Maxim)
  2. Document a comparison of the offerings
  3. Write about charging batteries
  4. Write about solar cells (How you use them?  Where do you buy them? How do you test them?)
  5. Write about buck-boost convertors
  6. Design the power supply for my IoT board

Solar Battery Charging PMICs

I started this whole process by making a google sheet with all of the characteristics that I care about.  I made the sheet public so that you can see the current version.

If you look in the spreadsheet you will notice that there are some holes.  And there are Im sure some missing rows.  If you know the answer to any of the open questions, or have other PMICs you are interested in, please either make a comment on this Article or send me an email at engineer@iotexpert.com

Development Kits

As you can see from the picture  below, I have a bunch of development kits.  Some were built by Semiconductor companies, some were built by third parties.  I have chips from Analog, Linear, Microchip, TI and ST.  There is one interesting company in China called Consonance (which I dont have boards for),  In addition, Fujistsu Electronics also makes a IC that I don’t have yet.

In the picture you can see that I have LTC3331, LTC3106, TI BQ25507, TI BQ25570, TI BQ24210, Microchip MCP73871, ST SPV1050 … for now.

In the coming articles look for detailed instructions on these chips, starting with the LTC3331.

Article Description
IoT Mailbox Introduction An introduction to the long series of articles about creating a new IoT System.
IoT Mailbox: Solar Battery Chargers & System Power Supplies

IoT Mailbox: An Introduction

Summary

On the days that my newspaper carrier decides to deliver the newspaper, you can be sure that it won’t be there before 4:00am or after 10:00am.  Why do I still get a newspaper?  Because my wife likes it.  The status of the delivery is a constant source of speculation in the morning.  Have you been out to the newspaper box?  Will you go?  etc.  So it seems only logical to make an IoT device that figures out if I have a newspaper.  Obviously this is a bit silly to put as much time and effort as I have into that simple task.  But, doing something cool has it own worth.  And it will give me a chance to use the new WICED XR (extended range) Bluetooth radio module CYBT-483039-02.

And here is a picture of the new module on the CYBT-483039-EVAL EZ-BT evaluation kit.

For this design I want

  1. A newspaper sensor (not sure what that will be)
  2. Waterproof case
  3. A temperature sensor
  4. A custom circuit board
  5. A solar battery charger
  6. The ability to program and debug the 20719 (which will be acting as a beacon)
  7. An OTA Bootloader
  8. A Real Time Clock
  9. A wifi/ble bridge (inside the house)
  10. Some cloud data capture and display
  11. An iOS App

So far, this project has been quite a rabbit hole as I don’t/didn’t know anything about battery power supplies.  Specifically energy harvesting solar powered lithium ion battery chargers and system power supply.  Unfortunately Cypress doesnt make an IC that performs this application … so if you send Mouser a few hundred dollars and they will send you a box of a bunch of different Solar PMIC Evaluation kits, ST, TI, Linear, Analog Devices, and Microchip. (which I will write about in detail later)

Architecture

Here is a picture of the architecture.

In the next Article I will start the process of learning about Solar Battery Charging PMICs.

Article Description
IoT Mailbox Introduction An introduction to the long series of articles about creating a new IoT System.
IoT Mailbox: Solar Battery Chargers & System Power Supplies

RS Components – The Inspiration

Earlier this year RS Components came to Kentucky to make some videos with Cypress (and me).  They have had a really cool impact.  This one has more than 1.1 million views.  How is that possible?  RS Components is a great parter.

Thanks,

Alan

Lesson 9 – WICED Bluetooth: Classic Serial Port

WICED Bluetooth Using the CYW20719

# Title Comment
0 A Two Hour WICED Bluetooth Class WICED Bluetooth Using the CYW20719 in all its glory
1 Resources Links to all of the Cypress WICED information including videos, application notes etc.
2 Your First Project Making Hello World & the Blinky LED
3 The Super Mux Tool Learning about platforms and the Super Mux Tool
4 Snips Using the example projects to learn Bluetooth
5 Bluetooth Designer Using the tool to customize a project and get going fast
6 The CCCD & Notification Writing back to the Central
7 Advertising  Beacon Building a beacon project to advertise your custom information 
8 Scanner Viewing the world around you
9 Bluetooth Classic SPP Using the Serial Port Profile to Transmit Lots of Data

Source code: 

  • git@github.com:iotexpert/wiced_bt_intro.git
  • https://github.com/iotexpert/wiced_bt_intro

 

Summary

In all of the previous examples I have been using Bluetooth Low Energy.  One of the great benefits of the Cypress CYW20719 is that it is a Combo Radio.  Combo means that it can use both Bluetooth Low Energy as well as Bluetooth Classic.  I am late to the Bluetooth game but as best I can tell Bluetooth Classic and Bluetooth Low Energy are exactly the same … except everything is different.  When Bluetooth was originally conceived, one of the principal functions was to act as “serial port wire cutter”.  Everywhere you looked there were devices that used a serial port wire, e.g. mice, printers, keyboards etc.

For this lesson we are going to dip back into the snip directory to get a Bluetooth Classic program to start with.  The program snip.bt.spp implements the Serial Port Profile (SPP).  The SPP is emulates a classic serial port.  It has all of the uart wires that we know and love including rx,tx,cts etc.  What this allows you to do is open up a high speed (much faster than BLE) connection.

To implement this lesson I will perform the following steps

  1. Make a new folder in the wiced_bt_class folder
  2. Copy the files from apps/snip/bt/spp into my new folder
  3. Create a make target and program it
  4. Make a connection using a Bluetooth serial port on my Mac
  5. Look at where the pin is set
  6. Examine the spp setup code
  7. Modify it to print out all the data sent to the SPP

Implement the SPP

 

Set the folder name to “spp”

Copy and past the files from the folder apps.snip.bt.spp


And paste them into your new spp folder

Create a make target for your spp project

Program the board with your project

Now tell the computer to open a classic connection by running file->open bluetooth

Select the “spp test”

Now press some keys on the new terminal window… and look at the output window of the “spp test”

Type in the pin code which is 0000.

But, how did I know the pin code?  Look at the source code.

uint8_t pincode[4] = { 0x30, 0x30, 0x30, 0x30 };

Now, when you press keys on the “Bluetooth serial terminal” you will see a not very helpful message on the CYW920719Q40EVB-01 terminal window.

I think that it would be better to print out the characters that the person types.  So lets figure out how this works.  In the application init function on line 251 there is a call to wiced_bt_spp_startup

void application_init(void)
{
    wiced_bt_gatt_status_t gatt_status;
    wiced_result_t         result;


#if SEND_DATA_ON_INTERRUPT
    /* Configure the button available on the platform */
    wiced_platform_register_button_callback( WICED_PLATFORM_BUTTON_1, app_interrupt_handler, NULL, WICED_PLATFORM_BUTTON_RISING_EDGE);

    // init timer that we will use for the rx data flow control.
    wiced_init_timer(&app_tx_timer, app_tx_ack_timeout, 0, WICED_MILLI_SECONDS_TIMER);
#endif

    app_write_eir();


    // Initialize SPP library
    wiced_bt_spp_startup(&spp_reg);

That function takes a pointer to a structure with a bunch of interesting things in it.  Notice that there is a function called “spp_rx_data_callback” that is called every time that data come in from the SPP.

wiced_bt_spp_reg_t spp_reg =
{
    SPP_RFCOMM_SCN,                     /* RFCOMM service channel number for SPP connection */
    MAX_TX_BUFFER,                      /* RFCOMM MTU for SPP connection */
    spp_connection_up_callback,         /* SPP connection established */
    NULL,                               /* SPP connection establishment failed, not used because this app never initiates connection */
    NULL,                               /* SPP service not found, not used because this app never initiates connection */
    spp_connection_down_callback,       /* SPP connection disconnected */
    spp_rx_data_callback,               /* Data packet received */
};

Now look at the function spp_rx_data_callback.  All it does is print out a message saying how much data and the hex value of the data.

wiced_bool_t spp_rx_data_callback(uint16_t handle, uint8_t* p_data, uint32_t data_len)
{
    int i;
//    wiced_bt_buffer_statistics_t buffer_stats[4];

//    wiced_bt_get_buffer_usage (buffer_stats, sizeof(buffer_stats));

//    WICED_BT_TRACE("0:%d/%d 1:%d/%d 2:%d/%d 3:%d/%d\n", buffer_stats[0].current_allocated_count, buffer_stats[0].max_allocated_count,
//                   buffer_stats[1].current_allocated_count, buffer_stats[1].max_allocated_count,
//                   buffer_stats[2].current_allocated_count, buffer_stats[2].max_allocated_count,
//                   buffer_stats[3].current_allocated_count, buffer_stats[3].max_allocated_count);

//    wiced_result_t wiced_bt_get_buffer_usage (&buffer_stats, sizeof(buffer_stats));

    WICED_BT_TRACE("%s handle:%d len:%d %02x-%02x\n", __FUNCTION__, handle, data_len, p_data[0], p_data[data_len - 1]);

#if LOOPBACK_DATA
    wiced_bt_spp_send_session_data(handle, p_data, data_len);
#endif
    return WICED_TRUE;
}

So,  How about instead of that message we just print out the data.

    //WICED_BT_TRACE("%s handle:%d len:%d %02x-%02x\n", __FUNCTION__, handle, data_len, p_data[0], p_data[data_len - 1]);

    for(int i=0;i<data_len;i++)
        WICED_BT_TRACE("%c",p_data[i]);

Now when I run the project and type I see the characters that I type coming out on the serial port.

Lesson 8 – WICED Bluetooth: The Advertising Scanner

WICED Bluetooth Using the CYW20719

# Title Comment
0 A Two Hour WICED Bluetooth Class WICED Bluetooth Using the CYW20719 in all its glory
1 Resources Links to all of the Cypress WICED information including videos, application notes etc.
2 Your First Project Making Hello World & the Blinky LED
3 The Super Mux Tool Learning about platforms and the Super Mux Tool
4 Snips Using the example projects to learn Bluetooth
5 Bluetooth Designer Using the tool to customize a project and get going fast
6 The CCCD & Notification Writing back to the Central
7 Advertising  Beacon Building a beacon project to advertise your custom information 
8 Scanner Viewing the world around you
9 Bluetooth Classic SPP Using the Serial Port Profile to Transmit Lots of Data

Source code: 

  • git@github.com:iotexpert/wiced_bt_intro.git
  • https://github.com/iotexpert/wiced_bt_intro

 

Summary

In the last lesson I showed you how to build a BLE Advertising Beacon.  In that lesson I used a program called the “AdvScanner” which ran on a CYW920719Q40EVB-01 and acted like a Bluetooth Sniffer.  In this lesson I’ll show you how to build a simpler version of that program to look for the L7_Advertiser we built in the last lesson.

The important concepts in this lesson are:

  1. BLE Scanning
  2. Parsing Advertising Packets

I am going to build a project that Scans for BLE Advertisers.  Then, I’ll add the ability to print out the advertising packet.  And finally, I will add filtering capability to only look for advertisers who are using the Cypress Manufacturers code.

The steps that we will follow are:

  1. Make a new project with WICED Bluetooth Designer called L8_Scanner
  2. Turn off the GATT Database
  3. Move it into your project folder
  4. Fix the WICED_BT_TRACE to use the PUART
  5. Create a make target and build it
  6. Add a new function that prints out Advertising Packets
  7. Update the l8_scanner_app_init function to remove Advertising
  8. Update the wiced_bt_config to never stop scanning
  9. Program the development kit and see what happens
  10. Update the newAdv function to print out the raw data in the advertising packet
  11. Program again and see all of the chaos
  12. Put a filter for the Advertisers using the Cypress MFG Code
  13. Program

Implement the Project

Create a new project called L8_Scanner using the Bluetooth Designer

Turn off the GATT Database and then press Generate Code

Move the project into the wiced_bt_class folder

Update the WICED_BT_TRACE to send output to the PUART

#if ((defined WICED_BT_TRACE_ENABLE) || (defined HCI_TRACE_OVER_TRANSPORT))
    /* Set the Debug UART as WICED_ROUTE_DEBUG_NONE to get rid of prints */
    //  wiced_set_debug_uart( WICED_ROUTE_DEBUG_NONE );

    /* Set Debug UART as WICED_ROUTE_DEBUG_TO_PUART to see debug traces on Peripheral UART (PUART) */
      wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_PUART );

    /* Set the Debug UART as WICED_ROUTE_DEBUG_TO_WICED_UART to send debug strings over the WICED debug interface */
    //wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_WICED_UART );
#endif

Modify the make target & program that was created by the BT Designer

Make a new function that will be called when WICED finds a new advertising packet.

void newAdv(wiced_bt_ble_scan_results_t *p_scan_result, uint8_t *p_adv_data)
{
    WICED_BT_TRACE("Found device %B\n",p_scan_result->remote_bd_addr);

}

Remove the start advertising from l8_scanner_app_init

/*
 * This function is executed in the BTM_ENABLED_EVT management callback.
 */
void l8_scanner_app_init(void)
{
    /* Initialize Application */
    wiced_bt_app_init();

    /* Allow peer to pair */
    wiced_bt_set_pairable_mode(WICED_TRUE, 0);

    /* Set Advertisement Data */
    //l8_scanner_set_advertisement_data();

    /* Start Undirected LE Advertisements on device startup.
     * The corresponding parameters are contained in 'wiced_bt_cfg.c' */
    /* TODO: Make sure that this is the desired behavior. */
    //wiced_bt_start_advertisements(BTM_BLE_ADVERT_UNDIRECTED_HIGH, 0, NULL);
    wiced_bt_ble_scan(BTM_BLE_SCAN_TYPE_HIGH_DUTY,FALSE,newAdv);
}

Update wiced_bt_config.c to never stop scanning.

        .high_duty_scan_duration =          0,                                                          /**< High Duty Scan Duration in seconds (0 for infinite) */

Program your development kit and see what happens.

Now lets update the program to print the advertising packets.

void newAdv(wiced_bt_ble_scan_results_t *p_scan_result, uint8_t *p_adv_data)
{

    uint8_t mfgLen;
    uint8_t* mfgData = wiced_bt_ble_check_advertising_data( p_adv_data,0xFF,&mfgLen);


    WICED_BT_TRACE("Found device %B ",p_scan_result->remote_bd_addr);

    uint8_t index=0;
    int fieldLength=p_adv_data[index];
    do {
        for(int i=0;i<=fieldLength;i++)
            WICED_BT_TRACE("%02X ",p_adv_data[index+i]);

        index = index + fieldLength + 1;
        fieldLength = p_adv_data[index];

    } while(fieldLength);

    WICED_BT_TRACE("\n");
}

Now program the development kit and see what happens.  Where I am sitting this is not very helpful because there are boatloads of advertisers.

Now let’s make one more change.  Instead of printing all of the packets let’s only look only at the ones that have Manufacturer data, the right length and the Cypress manufacturer id.

    uint8_t mfgLen;
    uint8_t* mfgData = wiced_bt_ble_check_advertising_data( p_adv_data,0xFF,&mfgLen);

    if(!(mfgData && mfgLen == 3 && mfgData[0] == 0x31 && mfgData[1]  == 0x01 ))
        return;

Now I only see my L7_Advertising project

Lesson 7 – WICED Bluetooth: Bluetooth Advertising

WICED Bluetooth Using the CYW20719

# Title Comment
0 A Two Hour WICED Bluetooth Class WICED Bluetooth Using the CYW20719 in all its glory
1 Resources Links to all of the Cypress WICED information including videos, application notes etc.
2 Your First Project Making Hello World & the Blinky LED
3 The Super Mux Tool Learning about platforms and the Super Mux Tool
4 Snips Using the example projects to learn Bluetooth
5 Bluetooth Designer Using the tool to customize a project and get going fast
6 The CCCD & Notification Writing back to the Central
7 Advertising  Beacon Building a beacon project to advertise your custom information 
8 Scanner Viewing the world around you
9 Bluetooth Classic SPP Using the Serial Port Profile to Transmit Lots of Data

Source code: 

  • git@github.com:iotexpert/wiced_bt_intro.git
  • https://github.com/iotexpert/wiced_bt_intro

 

Summary

Everywhere you go there are bunches of Bluetooth devices that are acting as beacons.  Apple has a standard called iBeacon.  Google has a standard called Eddystone.  Some companies use those standards, and some companies make proprietary beacons.  In this lesson we will build a beacon.

The important concepts in this lesson are:

  1. Advertising packet formats
  2. wiced_bt_cfg.c

The steps I will follow are:

  1. Run BT Designer
  2. Setup the device as “no gatt database”
  3. Move the project into the wiced_bt_class folder
  4. Edit the make target
  5. Fix the WICED_BT_TRACE to go to the PUART
  6. Run it
  7. Edit the wiced_bt_cfg.c to never timeout
  8. Setup no random address changing
  9. Add the manufacturing data uint8_t array and include the Cypress company code
  10. Change the start advertising call to BTM_BLE_ADVERT_NONCONN_HIGH, BLE_ADDR_PUBLIC
  11. Update the length of the advertising packet
  12. Update the set advertising packet to have the manufacturing data
  13. Add a button interrupt function
  14. Register the button interrupt

BLE Concepts

The Advertising Packet is a string of 3-31 bytes that is broadcast at a configurable interval. The packet is broken up into variable length fields. Each field has the form:

  • Length in bytes (not including the Length byte)
  • Type
  • Optional Data

The minimum packet requires the <<Flags>> field which is a set of flags that defines how the device behaves (e.g. is it connectable?). Here is a list of the other field Types that you can add:

/** Advertisement data types */
enum wiced_bt_ble_advert_type_e {
    BTM_BLE_ADVERT_TYPE_FLAG                        = 0x01,                 /**< Advertisement flags */
    BTM_BLE_ADVERT_TYPE_16SRV_PARTIAL               = 0x02,                 /**< List of supported services - 16 bit UUIDs (partial) */
    BTM_BLE_ADVERT_TYPE_16SRV_COMPLETE              = 0x03,                 /**< List of supported services - 16 bit UUIDs (complete) */
    BTM_BLE_ADVERT_TYPE_32SRV_PARTIAL               = 0x04,                 /**< List of supported services - 32 bit UUIDs (partial) */
    BTM_BLE_ADVERT_TYPE_32SRV_COMPLETE              = 0x05,                 /**< List of supported services - 32 bit UUIDs (complete) */
    BTM_BLE_ADVERT_TYPE_128SRV_PARTIAL              = 0x06,                 /**< List of supported services - 128 bit UUIDs (partial) */
    BTM_BLE_ADVERT_TYPE_128SRV_COMPLETE             = 0x07,                 /**< List of supported services - 128 bit UUIDs (complete) */
    BTM_BLE_ADVERT_TYPE_NAME_SHORT                  = 0x08,                 /**< Short name */
    BTM_BLE_ADVERT_TYPE_NAME_COMPLETE               = 0x09,                 /**< Complete name */
    BTM_BLE_ADVERT_TYPE_TX_POWER                    = 0x0A,                 /**< TX Power level  */
    BTM_BLE_ADVERT_TYPE_DEV_CLASS                   = 0x0D,                 /**< Device Class */
    BTM_BLE_ADVERT_TYPE_SIMPLE_PAIRING_HASH_C       = 0x0E,                 /**< Simple Pairing Hash C */
    BTM_BLE_ADVERT_TYPE_SIMPLE_PAIRING_RAND_C       = 0x0F,                 /**< Simple Pairing Randomizer R */
    BTM_BLE_ADVERT_TYPE_SM_TK                       = 0x10,                 /**< Security manager TK value */
    BTM_BLE_ADVERT_TYPE_SM_OOB_FLAG                 = 0x11,                 /**< Security manager Out-of-Band data */
    BTM_BLE_ADVERT_TYPE_INTERVAL_RANGE              = 0x12,                 /**< Slave connection interval range */
    BTM_BLE_ADVERT_TYPE_SOLICITATION_SRV_UUID       = 0x14,                 /**< List of solicitated services - 16 bit UUIDs */
    BTM_BLE_ADVERT_TYPE_128SOLICITATION_SRV_UUID    = 0x15,                 /**< List of solicitated services - 128 bit UUIDs */
    BTM_BLE_ADVERT_TYPE_SERVICE_DATA                = 0x16,                 /**< Service data - 16 bit UUID */
    BTM_BLE_ADVERT_TYPE_PUBLIC_TARGET               = 0x17,                 /**< Public target address */
    BTM_BLE_ADVERT_TYPE_RANDOM_TARGET               = 0x18,                 /**< Random target address */
    BTM_BLE_ADVERT_TYPE_APPEARANCE                  = 0x19,                 /**< Appearance */
    BTM_BLE_ADVERT_TYPE_ADVERT_INTERVAL             = 0x1a,                 /**< Advertising interval */
    BTM_BLE_ADVERT_TYPE_LE_BD_ADDR                  = 0x1b,                 /**< LE device bluetooth address */
    BTM_BLE_ADVERT_TYPE_LE_ROLE                     = 0x1c,                 /**< LE role */
    BTM_BLE_ADVERT_TYPE_256SIMPLE_PAIRING_HASH      = 0x1d,                 /**< Simple Pairing Hash C-256 */
    BTM_BLE_ADVERT_TYPE_256SIMPLE_PAIRING_RAND      = 0x1e,                 /**< Simple Pairing Randomizer R-256 */
    BTM_BLE_ADVERT_TYPE_32SOLICITATION_SRV_UUID     = 0x1f,                 /**< List of solicitated services - 32 bit UUIDs */
    BTM_BLE_ADVERT_TYPE_32SERVICE_DATA              = 0x20,                 /**< Service data - 32 bit UUID */
    BTM_BLE_ADVERT_TYPE_128SERVICE_DATA             = 0x21,                 /**< Service data - 128 bit UUID */
    BTM_BLE_ADVERT_TYPE_CONN_CONFIRM_VAL            = 0x22,                 /**< LE Secure Connections Confirmation Value */
    BTM_BLE_ADVERT_TYPE_CONN_RAND_VAL               = 0x23,                 /**< LE Secure Connections Random Value */
    BTM_BLE_ADVERT_TYPE_URI                         = 0x24,                 /**< URI */
    BTM_BLE_ADVERT_TYPE_INDOOR_POS                  = 0x25,                 /**< Indoor Positioning */
    BTM_BLE_ADVERT_TYPE_TRANS_DISCOVER_DATA         = 0x26,                 /**< Transport Discovery Data */
    BTM_BLE_ADVERT_TYPE_SUPPORTED_FEATURES          = 0x27,                 /**< LE Supported Features */
    BTM_BLE_ADVERT_TYPE_UPDATE_CH_MAP_IND           = 0x28,                 /**< Channel Map Update Indication */
    BTM_BLE_ADVERT_TYPE_PB_ADV                      = 0x29,                 /**< PB-ADV */
    BTM_BLE_ADVERT_TYPE_MESH_MSG                    = 0x2A,                 /**< Mesh Message */
    BTM_BLE_ADVERT_TYPE_MESH_BEACON                 = 0x2B,                 /**< Mesh Beacon */
    BTM_BLE_ADVERT_TYPE_3D_INFO_DATA                = 0x3D,                 /**< 3D Information Data */
    BTM_BLE_ADVERT_TYPE_MANUFACTURER                = 0xFF                  /**< Manufacturer data */
};

Here is an example of the advertising packet that we are going to generate

Implement the Project

Run BT Designer and create a new project called “L7_Advertising”

Turn off the GATT Database

Move the project into the wiced_bt_class folder

Edit the make target

Setup the the WICED_BT_TRACE to use the PUART

#if ((defined WICED_BT_TRACE_ENABLE) || (defined HCI_TRACE_OVER_TRANSPORT))
    /* Set the Debug UART as WICED_ROUTE_DEBUG_NONE to get rid of prints */
    //  wiced_set_debug_uart( WICED_ROUTE_DEBUG_NONE );

    /* Set Debug UART as WICED_ROUTE_DEBUG_TO_PUART to see debug traces on Peripheral UART (PUART) */
      wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_PUART );

    /* Set the Debug UART as WICED_ROUTE_DEBUG_TO_WICED_UART to send debug strings over the WICED debug interface */
    //wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_WICED_UART );
#endif

Run it

Now that we know it is working, Ill edit the wiced_bt_cfg.c to never timeout

        .high_duty_nonconn_duration =       0,                                                         /**< High Duty Non-Connectable Advertising Duration in seconds (0 for infinite) */

Setup no random address changing

    .rpa_refresh_timeout =                  WICED_BT_CFG_DEFAULT_RANDOM_ADDRESS_NEVER_CHANGE,         /**< Interval of random address refreshing - secs */

Now edit the L7_Advertising.c to add the manufacturing data uint8_t array

uint8_t manuf_data[] = {0x31,0x01,0x00};

Switch to non-connectable advertising

    wiced_bt_start_advertisements(BTM_BLE_ADVERT_NONCONN_HIGH, BLE_ADDR_PUBLIC, NULL);

Update the l7_advertising_set_advertisement_data function to have three elements in the advertising packet

    wiced_bt_ble_advert_elem_t adv_elem[3] = { 0 };

Add the Manufacturer information to the advertising packet

    /* Advertisement Element for Manufacturer Data */
    adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_MANUFACTURER;
    adv_elem[num_elem].len = sizeof(manuf_data);
    adv_elem[num_elem].p_data = manuf_data;
    num_elem++;

Add a button interrupt function

void buttonISR(void *data, uint8_t port_pin )
{

    manuf_data[2] += 1;
    l7_advertising_set_advertisement_data();
    WICED_BT_TRACE("Manufacturer Data = %d\n",manuf_data[2]);
}

Register the button interrupt

 wiced_hal_gpio_register_pin_for_interrupt( WICED_GPIO_PIN_BUTTON_1, buttonISR, NULL );
    wiced_hal_gpio_configure_pin( WICED_GPIO_PIN_BUTTON_1, ( GPIO_INPUT_ENABLE | GPIO_PULL_UP | GPIO_EN_INT_FALLING_EDGE ), GPIO_PIN_OUTPUT_HIGH );

Test using the AdvScanner

I have given you a project called the “AdvScanner”.  You can run it by creating a make target.

When I run the L7_Advertising project and press the buttons a few times my terminal will look like this

And when I look at the output of the scanner program you can see the advertising packet for the this project.  Notice that the last three bytes are 31 01 03.  The 03 is the count of button presses.

Lesson 6 – WICED Bluetooth: The Peripheral Comes Alive

WICED Bluetooth Using the CYW20719

# Title Comment
0 A Two Hour WICED Bluetooth Class WICED Bluetooth Using the CYW20719 in all its glory
1 Resources Links to all of the Cypress WICED information including videos, application notes etc.
2 Your First Project Making Hello World & the Blinky LED
3 The Super Mux Tool Learning about platforms and the Super Mux Tool
4 Snips Using the example projects to learn Bluetooth
5 Bluetooth Designer Using the tool to customize a project and get going fast
6 The CCCD & Notification Writing back to the Central
7 Advertising  Beacon Building a beacon project to advertise your custom information 
8 Scanner Viewing the world around you
9 Bluetooth Classic SPP Using the Serial Port Profile to Transmit Lots of Data

Source code: 

  • git@github.com:iotexpert/wiced_bt_intro.git
  • https://github.com/iotexpert/wiced_bt_intro

 

Summary

In the last lesson we built our first Bluetooth design using BT Designer.  In that lesson I showed you how to

  1. Build a project using BT Designer
  2. Start Advertising
  3. Get connected Central –> Peripheral
  4. Read & Write the data from the Central to the  Peripheral

In this lesson we are going to answer the question how does the Peripheral write data back to the Central by adding a button to our last project.  When the button is pressed it will send the state of the button (0 or 1) back to Central.

The important concepts in this lesson are

  1. BLE Notifications
  2. BLE Client Configuration Characteristic Descriptor
  3. How to manually modify the Gatt DB

I will follow these steps:

  1. Copy the project L5_BluetoothLED into L6_BluetoothLEDButton
  2. Rename all of the files to be L6_BluetoothLEDButton….
  3. Fix the makefile
  4. Create a make target and make sure that it still works
  5. Modify L6_BluetoothLEDButton_db.h to add UUID and Handles for the new Button characteristic
  6. Modify L6_BluetoothLEDButton_db.c to add the Button characteristic to the GATT Database
  7. Add initial value arrays for the Button characteristic, CCCD and User Description
  8. Add the Button values to the GATT lookup table
  9. Add connection id uint16_t connection_id
  10. Modify the connection handler l5_bluetoothled_connect_callback
  11. Create a button callback function
  12. Register the button callback

BLE Concepts

A Bluetooth Peripheral is allowed to send Notifications to a Central that a value in the GATT Database has changed.  However, it is only allowed to do this when the Client Characteristic Configuration Descriptor (CCCD) is set.  In other words a Central can register with a Peripheral that it is interested in seeing changes of Characteristics by writing a 0x01 into the CCCD.  The CCCD is just another value in the attribute database.

To setup a Characteristic for Notifications you need to modify the GATT Database by

  1. Adding the notification property to the Characteristic in the GATT Database
  2. Adding the CCCD to the GATT database

In the your program, when a value is changed, you should check to see if the CCCD is set, then send a notification if it is set.

Implement the Project

I am going to build this project on top of the code from L5_BluetoothLED.  So, start this project by copying the project L5_BluetoothLED into L6_BluetoothLEDButton by doing copy/paste

Rename all of the files to be L6_BluetoothLEDButton…. your project should look like this.

Fix the makefile.mk (because the file names have changed)

#
# This file has been automatically generated by the WICED 20719-B1 Designer.
#

APP_SRC = L6_BluetoothLEDButton.c
APP_SRC += L6_BluetoothLEDButton_db.c
APP_SRC += wiced_bt_cfg.c

C_FLAGS += -DWICED_BT_TRACE_ENABLE

# If defined, HCI traces are sent over transport/WICED HCI interface
C_FLAGS += -DHCI_TRACE_OVER_TRANSPORT

Create a make target and make sure that it still works

Modify L6_BluetoothLEDButton_db.h to create a UUID for the new Button characteristic

#define __UUID_L5SERVICE_BUTTON               0x2A, 0xbf, 0x86, 0xa6, 0xc8, 0x6c, 0x4e, 0xa5, 0xaa, 0x56, 0xbd, 0xac, 0x72, 0x80, 0x93, 0xa9

Modify L6_BluetoothLEDButton_db.h to add Handles for the  new Button characteristic

#define HDLC_L5SERVICE_BUTTON                      0x0030
#define HDLC_L5SERVICE_BUTTON_VALUE                0x0031
#define HDLD_L5SERVICE_BUTTON_USER_DESCRIPTION     0x0032
#define HDLD_L5SERVICE_BUTTON_CLIENT_CONFIGURATION 0x0033

Modify L6_BluetoothLEDButton_db.c to add the Button characteristic to the GATT Database

               /* Characteristic 'BUTTON' */

                CHARACTERISTIC_UUID128(HDLC_L5SERVICE_BUTTON, HDLC_L5SERVICE_BUTTON_VALUE,
                        __UUID_L5SERVICE_BUTTON, LEGATTDB_CHAR_PROP_READ | LEGATTDB_CHAR_PROP_NOTIFY,
                    LEGATTDB_PERM_READABLE ),

                    /* Descriptor 'Characteristic User Description' */
                    CHAR_DESCRIPTOR_UUID16 (HDLD_L5SERVICE_BUTTON_USER_DESCRIPTION,
                        UUID_DESCRIPTOR_CHARACTERISTIC_USER_DESCRIPTION, LEGATTDB_PERM_READABLE),


                /* Descriptor CCCD */
                CHAR_DESCRIPTOR_UUID16_WRITABLE(HDLD_L5SERVICE_BUTTON_CLIENT_CONFIGURATION,
                        UUID_DESCRIPTOR_CLIENT_CHARACTERISTIC_CONFIGURATION,
                        LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_REQ ),

Add initial value arrays for the Button characteristic, CCCD and User Description into L6_ButtonLED.c

uint8_t l5_bluetoothled_l5service_button[]                  = {0x01};
uint8_t l5_bluetoothled_l5service_button_user_description[] = "Button Value";
uint8_t l5_bluetoothled_l5service_button_cccd[]      = {0x00,0x00};

Add the Button values to the GATT lookup table

    {HDLC_L5SERVICE_BUTTON_VALUE,              1,                                                      1,                                                      l5_bluetoothled_l5service_button},
    {HDLD_L5SERVICE_BUTTON_USER_DESCRIPTION,   sizeof(l5_bluetoothled_l5service_button_user_description)-1, sizeof(l5_bluetoothled_l5service_button_user_description)-1, l5_bluetoothled_l5service_button_user_description},
    {HDLD_L5SERVICE_BUTTON_CLIENT_CONFIGURATION, 2,      2,      l5_bluetoothled_l5service_button_cccd},

Add connection id uint16_t connection_id

uint16_t connection_id=0;

Modify the connection handler l5_bluetoothled_connect_callback.  When you get a connection save it.

            connection_id = p_conn_status->conn_id;

and when you get a disconnect put it back to 0

          connection_id = 0;

Here is what the whole handler looks like now

/* GATT Connection Status Callback */
wiced_bt_gatt_status_t l5_bluetoothled_connect_callback( wiced_bt_gatt_connection_status_t *p_conn_status )
{
    wiced_bt_gatt_status_t status = WICED_BT_GATT_ERROR;

    if ( NULL != p_conn_status )
    {
        if ( p_conn_status->connected )
        {
            // Device has connected
            WICED_BT_TRACE("Connected : BDA '%B', Connection ID '%d'\n", p_conn_status->bd_addr, p_conn_status->conn_id );

            /* TODO: Handle the connection */
            connection_id = p_conn_status->conn_id;

        }
        else
        {
            // Device has disconnected
            WICED_BT_TRACE("Disconnected : BDA '%B', Connection ID '%d', Reason '%d'\n", p_conn_status->bd_addr, p_conn_status->conn_id, p_conn_status->reason );

            /* TODO: Handle the disconnection */
            connection_id = 0;

            /* restart the advertisements */
            wiced_bt_start_advertisements(BTM_BLE_ADVERT_UNDIRECTED_HIGH, 0, NULL);
        }
        status = WICED_BT_GATT_SUCCESS;
    }

    return status;
}

Create a button callback function

void buttonISR(void *data, uint8_t port_pin )
{

    l5_bluetoothled_l5service_button[0] = wiced_hal_gpio_get_pin_input_status(WICED_PLATFORM_BUTTON_1);

    if(l5_bluetoothled_l5service_button_cccd[0] & GATT_CLIENT_CONFIG_NOTIFICATION)
              {
                  wiced_bt_gatt_send_notification(connection_id, HDLC_L5SERVICE_BUTTON_VALUE, sizeof(l5_bluetoothled_l5service_button), l5_bluetoothled_l5service_button );

                  WICED_BT_TRACE( "Sent Button %d\n",l5_bluetoothled_l5service_button[0]);
   }
}

In the function l5_bluetoothled_app_init you need to register the button callback to trigger when the button is pressed

    wiced_hal_gpio_register_pin_for_interrupt( WICED_GPIO_PIN_BUTTON_1, buttonISR, NULL );
    wiced_hal_gpio_configure_pin( WICED_GPIO_PIN_BUTTON_1, ( GPIO_INPUT_ENABLE | GPIO_PULL_UP | GPIO_EN_INT_BOTH_EDGE ), GPIO_PIN_OUTPUT_HIGH );

Test using CySmart

 

Click on the “Unknown Service”

Click on the second characteristic.  (we know that is the one because it is Read and Notify)

Now you can press “Read”

 

After clicking the read button and you can see that the value is 0x01 (because you are not pressing the button).  If you were pressing it you would see 0x00

Now press Notify and you should see the value change each time you press the button

 

Lesson 5 – WICED Bluetooth: Bluetooth Designer – Turn up the Radio!

WICED Bluetooth Using the CYW20719

# Title Comment
0 A Two Hour WICED Bluetooth Class WICED Bluetooth Using the CYW20719 in all its glory
1 Resources Links to all of the Cypress WICED information including videos, application notes etc.
2 Your First Project Making Hello World & the Blinky LED
3 The Super Mux Tool Learning about platforms and the Super Mux Tool
4 Snips Using the example projects to learn Bluetooth
5 Bluetooth Designer Using the tool to customize a project and get going fast
6 The CCCD & Notification Writing back to the Central
7 Advertising  Beacon Building a beacon project to advertise your custom information 
8 Scanner Viewing the world around you
9 Bluetooth Classic SPP Using the Serial Port Profile to Transmit Lots of Data

Source code: 

  • git@github.com:iotexpert/wiced_bt_intro.git
  • https://github.com/iotexpert/wiced_bt_intro

 

Summary

In this lesson we are going to build the simplest project that I could think of… turning an LED on/off with Bluetooth Low Energy.

The important BLE concepts are

  1. What is a Central / Peripheral
  2. What is Advertising
  3. What is a GATT Database

The important WICED Bluetooth Concepts are:

  1. How do you run WICED Bluetooth Designer
  2. What is the structure of a WICED Bluetooth Project
  3. What is a Callback
  4. How is the GATT Database Implemented
  5. How to run CySmart

The steps that we will follow are:

  1. Run BT Designer
  2. Create a project called L5_BluetoothLED
  3. Go to the characteristics page
  4. Add a vendor specific service
  5. Name the Service L5Service
  6. Add an optional characteristic that is vendor specific
  7. Name it RED
  8. Make it 1 byte with an initial value of 01
  9. Set it up for host write
  10. Add a user description to the characteristic
  11. Generate the code
  12. Move the folder to the wiced_bt_class folder
  13. Fix the three include problems
  14. Reset the debug UART to PUART
  15. When there is a write, change the value of the WICED_LED_1 GPIO
  16. Test

BLE Concepts

In the world of BLE there are two sides of every connection

  • The Central – typically a cellphone
  • The Peripheral – your WICED device

Centrals listen for Peripherals that are Advertising.  Advertising is a periodic packet of up to 31 bytes of information that a Peripheral will send out to make it presence known.  When a Central hears the Advertising packets of a Peripheral that is “interesting” it can initiate a connection.

Once a connection is made, how do you exchange information?  The answer is that a Peripheral has a database running inside of it.  The database is called a “GATT database”.   A Central can perform “Service Discovery” to find all of the legal stuff in the database.  The GATT database is organized into one or more “Services” that have one or more “Characteristics”.  For instance a Heart Rate Monitor might have a “Heart Rate Service” with two characteristics, one for heart rate and one for battery level.

There are two types of Services.  Ones that are specified by the Bluetooth SIG, like heartrate.  And vendor specific custom services.

Run Bluetooth Designer

The Bluetooth Designer is a GUI tool that we built into Eclipse.  It allows you to configure some of the fundamental Bluetooth feature (like the GATT Database) and then automatically generate the code.  Start Bluetooth Designer by running File->New->WICED Bluetooth Designer.

Since this is Lesson 5 and we are going to write and LED… call the project “L5_BluetoothLED”

Once you start BT Designer, you screen should look like this.  The project is going to be a BLE only project.

The Characteristics button lets you setup the GATT database.

Add a service by selecting vendor specific service and then hitting the “+”

I’ll call the service “L5Service”

Next add a characteristic by selecting “vendor specific characteristic” and pressing “+”

Change the name to “RED”, Make the device role “Host write to or reads from service”.  Make the size 1 byte and set the initial value to 01 (it must be 01 not 1 or 001)

When we are looking at this remotely you would like to be able to see the user description.  So click that tab and give it a description.

Press Generate Code button.  You will end up with a folder in the top level apps directory.  I don’t like this, so lets move it into our class projects folder.  You can do this by dragging the folder to the wiced_bt_class folder.  Now it should look like this:

Unfortunately, there are three little issues that this creates which need to be fixed.  First, you need to fix L5_BluetoothLED.c as this include is wrong.

#include "../wiced_bt_class/L5_BluetoothLED/L5_BluetoothLED_db.h"

And change it to:

#include "L5_BluetoothLED_db.h"

Next edit L5_BluetoothLED_db.h and add the #include “wiced.h”

#include "wiced.h"

Finally edit the L5_BluetoothLED_db.c to fix the same include problem.

#include "../wiced_bt_class/L5_BluetoothLED/L5_BluetoothLED_db.h"

It should be like this.

#include "L5_BluetoothLED_db.h"

Now edit the make target that was created by the BT Designer and change it to:

Remember in the earlier lesson I showed you about the WICED HCI UART and the WICED PUART.  Well by default the WICED_BT_TRACE is setup to go to the HCI UART.  So, lets fix the output of BT_TRACE to go to the PUART by changing the file “L5_BluetoothLED.c”

#if ((defined WICED_BT_TRACE_ENABLE) || (defined HCI_TRACE_OVER_TRANSPORT))
    /* Set the Debug UART as WICED_ROUTE_DEBUG_NONE to get rid of prints */
    //  wiced_set_debug_uart( WICED_ROUTE_DEBUG_NONE );

    /* Set Debug UART as WICED_ROUTE_DEBUG_TO_PUART to see debug traces on Peripheral UART (PUART) */
      wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_PUART );

    /* Set the Debug UART as WICED_ROUTE_DEBUG_TO_WICED_UART to send debug strings over the WICED debug interface */
    //wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_WICED_UART );
#endif

The last thing that we want to do is fix it so that when the Central writes a new value into the RED LED characteristic we should write the GPIO to the new value.  In L5_BluetoothLED.c make this change.

     case HDLC_L5SERVICE_RED_VALUE:
                       WICED_BT_TRACE("LED = %d\n",l5_bluetoothled_l5service_red[0]);
                       wiced_hal_gpio_set_pin_output(WICED_GPIO_PIN_LED_2,l5_bluetoothled_l5service_red[0]);
                       break;

Now build the project and see what happens.  The first testing step will be to open CySmart.  You can see that a device called “L5_BluetoothLED” is advertising.

When I click it, you can see that there is a GattDB.

When I click on the database, I can see that there is only one service (which makes sense as we setup only one)

Click on the Service and you can see that there is only one characteristic in the service… and its value is 01.

When you click the descriptor button you can see that there is a Characteristic User Description

 

And finally the value is “Red LED Value”.  That is what we setup.

When you click back … then click on the write it will bring up this window where I can send a new value.

Now the value is 0x00 and the RED LED is on (remember from earlier that it is active low so that makes sense)

 

And when I look at the terminal I can see two writes (I wrote again before I took this screen shot)

A Tour of the Source Code

The GATT Database is in the file L5_BluetoothLED_db.c

const uint8_t gatt_database[] = // Define GATT database
{
    /* Primary Service 'Generic Attribute' */
    PRIMARY_SERVICE_UUID16 (HDLS_GENERIC_ATTRIBUTE, UUID_SERVICE_GATT),

    /* Primary Service 'Generic Access' */
    PRIMARY_SERVICE_UUID16 (HDLS_GENERIC_ACCESS, UUID_SERVICE_GAP),

        /* Characteristic 'Device Name' */
        CHARACTERISTIC_UUID16 (HDLC_GENERIC_ACCESS_DEVICE_NAME, HDLC_GENERIC_ACCESS_DEVICE_NAME_VALUE,
            UUID_CHARACTERISTIC_DEVICE_NAME, LEGATTDB_CHAR_PROP_READ,
            LEGATTDB_PERM_READABLE),

        /* Characteristic 'Appearance' */
        CHARACTERISTIC_UUID16 (HDLC_GENERIC_ACCESS_APPEARANCE, HDLC_GENERIC_ACCESS_APPEARANCE_VALUE,
            UUID_CHARACTERISTIC_APPEARANCE, LEGATTDB_CHAR_PROP_READ,
            LEGATTDB_PERM_READABLE),

    /* Primary Service 'L5Service' */
    PRIMARY_SERVICE_UUID128 (HDLS_L5SERVICE, __UUID_L5SERVICE),

        /* Characteristic 'RED' */
        CHARACTERISTIC_UUID128_WRITABLE (HDLC_L5SERVICE_RED, HDLC_L5SERVICE_RED_VALUE,
            __UUID_L5SERVICE_RED, LEGATTDB_CHAR_PROP_READ | LEGATTDB_CHAR_PROP_WRITE,
            LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_REQ),

            /* Descriptor 'Characteristic User Description' */
            CHAR_DESCRIPTOR_UUID16 (HDLD_L5SERVICE_RED_USER_DESCRIPTION,
                UUID_DESCRIPTOR_CHARACTERISTIC_USER_DESCRIPTION, LEGATTDB_PERM_READABLE),

};

Each row in the Database table has a unique “Handle” that is defined in the L5_BluetoothLED_db.h

#define __UUID_L5SERVICE                      0x30, 0x9d, 0x7f, 0x29, 0x73, 0xca, 0x4f, 0xfd, 0xa5, 0x68, 0x17, 0xd8, 0x90, 0x67, 0x7f, 0x35
#define __UUID_L5SERVICE_RED                  0x29, 0xbf, 0x86, 0xa6, 0xc8, 0x6c, 0x4e, 0xa5, 0xaa, 0x56, 0xbd, 0xac, 0x72, 0x80, 0x93, 0xa9

// ***** Primary Service 'Generic Attribute'
#define HDLS_GENERIC_ATTRIBUTE                0x0001

// ***** Primary Service 'Generic Access'
#define HDLS_GENERIC_ACCESS                   0x0014
// ----- Characteristic 'Device Name'
#define HDLC_GENERIC_ACCESS_DEVICE_NAME       0x0015
#define HDLC_GENERIC_ACCESS_DEVICE_NAME_VALUE 0x0016
// ----- Characteristic 'Appearance'
#define HDLC_GENERIC_ACCESS_APPEARANCE        0x0017
#define HDLC_GENERIC_ACCESS_APPEARANCE_VALUE  0x0018

// ***** Primary Service 'L5Service'
#define HDLS_L5SERVICE                        0x0028
// ----- Characteristic 'RED'
#define HDLC_L5SERVICE_RED                    0x0029
#define HDLC_L5SERVICE_RED_VALUE              0x002A
// ===== Descriptor 'User Description'
#define HDLD_L5SERVICE_RED_USER_DESCRIPTION   0x002B

Each characteristic value is held in one of the uint8_t arrays found in “L5_BluetoothLED.c”

/*******************************************************************
 * GATT Initial Value Arrays
 ******************************************************************/
uint8_t l5_bluetoothled_generic_access_device_name[]     = {'L','5','_','B','l','u','e','t','o','o','t','h','L','E','D'};
uint8_t l5_bluetoothled_generic_access_appearance[]      = {0x00,0x00};
uint8_t l5_bluetoothled_l5service_red[]                  = {0x01};
uint8_t l5_bluetoothled_l5service_red_user_description[] = {'R','E','D',' ','L','e','d',' ','V','a','l','u','e'};

/*******************************************************************
 * GATT Lookup Table
 ******************************************************************/

/* GATT attribute lookup table                                */
/* (attributes externally referenced by GATT server database) */
gatt_db_lookup_table l5_bluetoothled_gatt_db_ext_attr_tbl[] =
{
    /* { attribute handle,                  maxlen,                                                 curlen,                                                 attribute data } */
    {HDLC_GENERIC_ACCESS_DEVICE_NAME_VALUE, 15,                                                     15,                                                     l5_bluetoothled_generic_access_device_name},
    {HDLC_GENERIC_ACCESS_APPEARANCE_VALUE,  2,                                                      2,                                                      l5_bluetoothled_generic_access_appearance},
    {HDLC_L5SERVICE_RED_VALUE,              1,                                                      1,                                                      l5_bluetoothled_l5service_red},
    {HDLD_L5SERVICE_RED_USER_DESCRIPTION,   sizeof(l5_bluetoothled_l5service_red_user_description), sizeof(l5_bluetoothled_l5service_red_user_description), l5_bluetoothled_l5service_red_user_description},
};

 

 

Lesson 4 – WICED Bluetooth: Using Snips

WICED Bluetooth Using the CYW20719

# Title Comment
0 A Two Hour WICED Bluetooth Class WICED Bluetooth Using the CYW20719 in all its glory
1 Resources Links to all of the Cypress WICED information including videos, application notes etc.
2 Your First Project Making Hello World & the Blinky LED
3 The Super Mux Tool Learning about platforms and the Super Mux Tool
4 Snips Using the example projects to learn Bluetooth
5 Bluetooth Designer Using the tool to customize a project and get going fast
6 The CCCD & Notification Writing back to the Central
7 Advertising  Beacon Building a beacon project to advertise your custom information 
8 Scanner Viewing the world around you
9 Bluetooth Classic SPP Using the Serial Port Profile to Transmit Lots of Data

Source code: 

  • git@github.com:iotexpert/wiced_bt_intro.git
  • https://github.com/iotexpert/wiced_bt_intro

 

Summary

In this lesson I am going to show you how to NOT write all of your own code and still get the job done.  In this lesson we are going to do three things.

  1. Examine & Run the hal_gpio snip
  2. Examine & Run the hal_i2c_master snip
  3. Copy the hal_i2c_master snip and make it “more better”

To modify the hal_i2c_master snip I will

  1. Make a new folder called L4_Accelerometer
  2. Copy the makefile.mk and hal_i2c_master.c into the L4_Accelerometer folder
  3. Create a new make target and make sure that things still work
  4. Look at the LSM9DS1 datasheet
  5. Update the function initialize_app to startup the Accelerometer and speed up the polling
  6. Update the function comboread_cb to read the Acceleration registers and print out the values

Run hal_gpio

If you dont already have a make target for snip.hal.hal_gpio create one and then program the board.

Notice that the light blinking will change speeds if you press the button.  Let’s look at the code that does this:

At the beginning it sets up a timer

        // Initialize timer to control the pin toggle frequency
        if (wiced_init_timer(&hal_gpio_app_timer, &hal_gpio_app_timer_cb, 0, WICED_SECONDS_PERIODIC_TIMER) == WICED_SUCCESS)
        {
            if (wiced_start_timer(&hal_gpio_app_timer, LED_BLINK_FREQ_A_IN_SECONDS) != WICED_SUCCESS)
            {
                WICED_BT_TRACE("Seconds Timer Error\n");
            }
        }

The timer calls this function each time the timer expires.

/*
 * The function invoked on timeout of app. seconds timer.
 */
void hal_gpio_app_timer_cb(uint32_t arg)
{
    static uint32_t wiced_seconds = 0; /* number of seconds elapsed */
    uint8_t index = 0;

    wiced_seconds++;

    if (wiced_seconds & 1)
    {
        for (index = 0; index < sizeof(output_pin_list); index++)
        {
            wiced_hal_gpio_set_pin_output(output_pin_list[index], GPIO_PIN_OUTPUT_LOW);
        }
    }
    else
    {
        for (index = 0; index < sizeof(output_pin_list); index++)
        {
            wiced_hal_gpio_set_pin_output(output_pin_list[index], GPIO_PIN_OUTPUT_HIGH);
        }
    }
}

And when the button is pressed all it does is switch back and forth between two different intervals for the timer.  And after the switch it restarts the timer.

/*
 * Handle interrupt generated due to change in the GPIO state
 */
void hal_gpio_app_interrrupt_handler(void *data, uint8_t pin)
{
    static uint32_t blink_freq = LED_BLINK_FREQ_A_IN_SECONDS;

    // toggle LED blink rate upon each button press
    if (blink_freq == LED_BLINK_FREQ_A_IN_SECONDS)
    {
        blink_freq = LED_BLINK_FREQ_B_IN_SECONDS;
    }
    else
    {
        blink_freq = LED_BLINK_FREQ_A_IN_SECONDS;
    }

    if (wiced_stop_timer(&hal_gpio_app_timer) == WICED_SUCCESS)
    {
        wiced_start_timer(&hal_gpio_app_timer, blink_freq);
    }

    // clear the interrupt status
    wiced_hal_gpio_clear_pin_interrupt_status(pin);
}

Run hal_i2c_master

This CYW920719Q40EVB_01 development kit has an I2C LSM9DS1 accelerometer on it.  And I noticed that when looking around in the snips that the Snip called “hal_i2c_master.c” appears to talk to the chip.  Here is a little section of the comments from the top of the snip

 *
 * WICED sample application for I2C Master usage
 *
 * This application demonstrates how to use I2C driver interface
 * to send and receive bytes or a stream of bytes over the I2C hardware as a master.
 * The on-board LSM9DS1 motion sensor acts as the I2C slave

So, lets run the snip and see what happens.  If you don’t have a make target… well then make one.

Then make the make target.

It turns out that “0” is a bug in the example project.  And printing out the WHO_AM_I register isnt really very interesting.

Modify the hal_i2c_master.c Create a Better Project

I don’t like making changes inside of the WICED SDK files.  But, I want to fix the bug and printout something more interesting.  So start by creating a new folder in the wiced_bt_class folder

Type in the directory name L4_Accelerometer (notice in the screenshot below I mistyped it)

Select the makefile.mk and the hal_i2c_master.c then right click copy the files.

Then select the L4_Accelerometer folder and pick paste.

Create a make target for the L4_Accelerometer

Build it to make sure it still works.

Now that we have a base to stand-on.  Let’s have a look at the data sheet.  I have used these before and I know that you need to turn on the Accelerometer to give you anything interesting.  Turns out CTRL_REG_6_XL is the control register we need.

The other interesting registers are the actual output of the accelerometer.  That is 0x28 –> 0x2D

Start by modifying the function initialize_app to turn on the accelerometer by writing 0x40 to register 0x20

uint8_t status;
    // Turn on Accelerometer - Register 0x20... 2g accelerometer on @ 50hz
    uint8_t data[] = {0x20, 0x40};
    status = wiced_hal_i2c_write(data,sizeof(data),LSM9DS1_ACC_GYRO_I2C_ADDRESS);

I dont really like printing the values every two seconds so I will modify the timer:

  • Make it a milisecond timer
  • Set it to print every 500ms
if ( WICED_SUCCESS == wiced_init_timer( &seconds_timer, &comboread_cb, 0, WICED_MILLI_SECONDS_PERIODIC_TIMER )) {
        if ( WICED_SUCCESS != wiced_start_timer( &seconds_timer, 500 )) {
            WICED_BT_TRACE( "Seconds Timer Error\n\r" );
        }
    }

Here is the whole function initialize_app together

void initialize_app( void )
{
    wiced_hal_i2c_init();
    uint8_t status;

    // Turn on Accelerometer - Register 0x20... 2g accelerometer on @ 50hz
    uint8_t data[] = {0x20, 0x40};
    status = wiced_hal_i2c_write(data,sizeof(data),LSM9DS1_ACC_GYRO_I2C_ADDRESS);


    /* register callback for button available on the platform */
    wiced_platform_register_button_callback( WICED_PLATFORM_BUTTON_1, button_cb, NULL, WICED_PLATFORM_BUTTON_RISING_EDGE);

    current_speed = wiced_hal_i2c_get_speed();

    WICED_BT_TRACE("Default I2C speed: %d KHz\n", (CLK_FREQ/current_speed));

    /*Start a timer for POLL_TIMER seconds*/

    if ( WICED_SUCCESS == wiced_init_timer( &seconds_timer, &comboread_cb, 0, WICED_MILLI_SECONDS_PERIODIC_TIMER )) {
        if ( WICED_SUCCESS != wiced_start_timer( &seconds_timer, 500 )) {
            WICED_BT_TRACE( "Seconds Timer Error\n\r" );
        }
    }

}

Next I need to modify the comboread_cb callback.  It will

  • Setup a structure to hold the three acceleration values (Line 145)
  • Then it will read from the LSM9DS1 (Line 152)
  • Then print them (Line 156)
/******************************************************************************
 * This function reads the value from I2C slave and prints it
 *****************************************************************************/

void comboread_cb (uint32_t arg)
{
    UINT8  status = 0xFF;
    UINT8 reg_add = 0x28; // Acceleromter register

    typedef struct {
        int16_t ax;
        int16_t ay;
        int16_t az;
    } __attribute__((packed)) accel_val_t;

    accel_val_t data;
    status = wiced_hal_i2c_combined_read((UINT8 *)&reg_add, sizeof(UINT8), (uint8_t *)&data, sizeof(data), LSM9DS1_ACC_GYRO_I2C_ADDRESS);

    if(I2CM_SUCCESS == status) {

        WICED_BT_TRACE("Ax=%d Ay=%d Az=%d\n",data.ax,data.ay,data.az);
    }else if(I2CM_OP_FAILED == status) {
        WICED_BT_TRACE("I2C comboread operation failed\r\n");
    }else if(I2CM_BUSY == status) {
        WICED_BT_TRACE("I2C busy\r\n");
    }else{
        WICED_BT_TRACE("Unknown status from I2C\r\n");
    }

}

Now double click the make target and make sure that everything is working.