NAV Navbar

Getting Started with Bluetooth Mesh - AN227069

This application note introduces Bluetooth Mesh and its key concepts and describes how to get started with Cypress’ BLE Mesh solution to design your own BLE Mesh-enabled applications. Cypress is a world-leader in connectivity solutions for Internet of Things (IoT) applications, combining best-in-class silicon platforms with the industry’s most broadly deployed Bluetooth stack. This combination allows you to deploy successful BLE Mesh-enabled products with minimum development costs and with a rapid cycle time.

All documentation can be accessed at the Cypress Bluetooth Mesh website.

Mesh-Qualified Silicon Devices

Cypress offers a portfolio of Mesh-qualified Bluetooth devices as follows:

Table 1. Mesh-Qualified Bluetooth Device Features

tab1

Table 1 provides the list of these devices and their capabilities. For the most up-to-date details on Cypress Mesh-qualified devices, visit the Cypress BLE Mesh Webpage.

Mesh-Qualified EZ-BT Bluetooth Modules

Figure 1. EZ-BT Module Marketing Part Numbering Format

Cypress provides a variety of certified Bluetooth Mesh-Qualified modules to reduce hardware development cost and time. Every module within the EZ-BT Module family has a unique Marketing Part Number (MPN) used for ordering.

The Silicon device and the corresponding MPNs are listed below:

Silicon Device MPN
CYW20706 CYBT-343026-01
CYBT-333032-02
CYBT-343047-02
CYBT-343151-02
CYW20707 CYBT-353027-02
CYW20719 CYBT-423028-02
CYBT-413034-02
CYBT-483039-02
CYBT-213043-02

Table 2. EZ-BT Module MPN Features and Capabilities

tab2

The MPN format is shown in Figure 1. Table 2 elaborates the features and capabilities of each EZ-BT Module MPN available from Cypress. For the latest list of modules available, visit the Cypress Bluetooth website.

Mesh-Qualified EZ-BT Module and Silicon Datasheets

EZ-BT WICED Module and silicon datasheets list the features, pinouts, device-level specifications, and fixed-function peripheral electrical specifications of Cypress module and silicon products. Visit the Cypress BLE and Bluetooth website to access all datasheets for EZ-BT WICED Modules and silicon devices.

The CYBT-213043-MESH kit referred to in this application note utilizes the CYBT-213043-02 certified module. The datasheet for this module can be accessed here. This datasheet can also be accessed on the Cypress BLE and Bluetooth website.

Bluetooth Mesh Evaluation Boards

CYBT-213043-MESH is a Mesh evaluation kit that features the CYBT-213043-02 EZ-BT certified module, based on the CYW20819 silicon device. This kit includes four Mesh evaluation boards, allowing you to develop a small Mesh network without the need to purchase multiple evaluation boards. Each board features an Ambient Light Sensor (ALS), a PIR motion sensor and lens, a thermistor, an RGB LED, a user switch and an on-board programmer (USB-to-UART). To learn more about the kit and available resources, visit the CYBT-213043-MESH EZ-BT Module Mesh Evaluation Kit Webpage.

If you are designing Bluetooth Mesh products based on a device or module other than the CYW20819, you can use the respective device’s evaluation kit. Each EZ-BT WICED Module and silicon device offers a low-cost Arduino-compatible evaluation board, providing an easy-to-use vehicle to develop and evaluate Bluetooth Mesh using the EZ BT WICED Modules and silicon without requiring custom hardware design. Visit the Cypress Bluetooth Mesh website to view and purchase Cypress evaluation boards.

Cypress Developer Community for Bluetooth Mesh and Technical Support

Whether you’re a customer, partner, or a developer interested in designing Bluetooth Mesh products, the Cypress ModusToolbox Bluetooth Community offers you a place to learn, share, and engage with both Cypress experts and other embedded engineers around the world. If you have any technical questions, you can post them on Cypress Developer Community forums that are actively managed by Cypress engineers.

BLE Mesh Overview

Bluetooth Low Energy (BLE) has emerged as the preferred standard for IoT connectivity. The BLE standard’s inherent low-power operation coupled with installed support on smart phones and personal computers have been a driving force behind its growth in IoT applications.

Traditional BLE applications use point-to-point communication, where each pair of devices sends data to and from each other. Each of these connections utilizes a GAP Central and a GAP Peripheral role to accomplish the communication.

In contrast, in a Mesh network, every device can communicate with every other device within the same network. This capability extends the overall communication range beyond the range of each individual device. In a Bluetooth Mesh implementation, messages are sent using advertising packets. By using advertising packets for network communication, the relaying of network messages requires no connections to be made to share information. Rather, data is broadcast by a transmitting device using these advertising packets and is received by any device that is part of the network and that is within the range of the transmitter. Devices that are provisioned into a BLE Mesh network are called "nodes". Bluetooth Mesh defines various types of nodes; some utilized for range extension and network coverage while others are optimized for low-power operation and only wake when they need to.

BLE Mesh is emerging as a preferred home automation technology driven by the fact that BLE Mesh nodes can be controlled directly from a mobile phone or PC without the need to install a network gateway. The BLE Mesh specification has been defined to provide standards-based operating models tailored to home and industrial automation use cases. Standard message formats for defined use cases (models) enable rapid deployment and interoperability assurance with other BLE Mesh products.

BLE Mesh Nodes and Feature Types

Figure 2. BLE Mesh Network and Node Types

BLE Mesh has several node/feature types. Each node can include multiple features if desired. This section provides an overview of the different BLE Mesh node types and various features that can be employed on these nodes.

Relay Node

The Relay feature of a node includes the ability to relay messages over the advertising bearer. In a Mesh network, most nodes include this feature unless they are low-power nodes (LPNs). An example of a Relay feature in use is a smart light bulb or light switch. Typically, any node that is wall-powered is likely to be a Relay Node as they have the power needed to listen continuously for advertising packets and relay them to additional nodes in the network.

Low-Power Node (LPN)

A Low-Power Node is a critical feature for BLE Mesh-enabled applications. Low-Power Nodes operate in low duty cycles, by working and communicating in conjunction with Friend Nodes that collect messages on the LPN’s behalf. The LPN will ping its Friend node at a defined interval to check for pending messages, and after communication with the Friend Node, it will go back to a low-power sleep state to conserve power. Any battery powered application, such as a glass door sensor or smoke detector can be a low-power node. With the BLE Mesh low-power feature, even a coin-cell battery is often sufficient to power a Low-Power Node for over a year.

Friend Node

A node with the Friend feature will listen to any messages that are relayed in the network and are intended for its associated LPNs. The Friend node will store these messages and deliver them to the associated LPNs when the LPNs wake and query the Friend node. Since a Friend Node needs to store messages for one or more LPN, the Friend Node may require more memory than other node types. The amount of memory required is dependent on the amount of data/commands required to be stored on the Friend node that will be communicated to the LPN during a polling operation.

Proxy Node

BLE Mesh networks relay messages over an advertising bearer. The Proxy feature is the ability of a node to relay messages between the GATT (General ATTribute) and advertising bearers. This feature allows devices, such as smartphone, that support BLE but not BLE Mesh, to communicate with a Mesh network. A Proxy Node is the entry point into the Mesh network for those devices that don’t directly support BLE Mesh. Any node that supports the Proxy feature can act as the interface for a smartphone/PC over a GATT connection.

Provisioner

The Provisioning feature is a key to enable a secure BLE Mesh network. Provisioning is the process of adding a new node to a network. When your consumer purchases a BLE Mesh-enabled device, they need to have the ability to add this device to their network. This requires several steps to ensure that unintended devices are not provisioned to the network. A device that is unprovisioned will send beacons at a predetermined interval, and the provisioning device will initiate the provisioning process once the unprovisioned device is found and selected. BLE Mesh uses the Elliptic Curve Diffie Hellman (ECDH) algorithm to exchange keys for secure communication to ensure that your network and the provisioning of devices into it is secure.

BLE Mesh Operation and Key Concepts

Managed Flood

BLE Mesh uses a managed flood operation to transfer messages. Managed flood is inherently a multi-path implementation that adds enough redundancy to ensure that a message reaches its destination. A brute force flood implementation is one where every node blindly relays (retransmits) any message that it has received. Conversely, the BLE managed flood operation is designed to prevent devices from relaying previously received messages by adding all messages to a cached list. When a message is received, it is checked against the list and ignored if already present. If the message has not been previously received, then it is added to the cache so that it can be ignored in the future. Each message includes a Time to Live (TTL) value that limits the number of times a message can be relayed. Each time a message is received and then relayed (up to a maximum of 126 times) by a device, the TTL value is decremented by 1.

Publish- and Subscription-Based Communication

A Publisher Node sends messages, and only nodes that have subscribed to the Publisher will act on these messages. This ensures that different types of products can coexist in a network without being bothered by messages from devices they do not need to listen to. An example of this operation is different rooms within your home, with each room subscribing to messages related to the specific light switches for that room. In addition, messages can be either unicast, multicast, and/or broadcast, meaning that a message can reach one, a few, or all nodes in the network.

Figure 3. Publish and Subscribe Example

Elements

Elements consist of entities that define a node’s functionality. Each node can have one or more Elements. Every node has at least one Element called the “Primary Element”. For example, a dimmable light bulb generally has one Element; this Element can expose one or more functionalities such as ON/OFF and level (brightness) control. In this example, the Light Lightness Server Model is used to achieve the ON/OFF and level control functionality.

Another example is a dimmable light bulb that also includes an occupancy sensor. In this example, the node will have two Elements: one for the lighting function and the other for the sensor function. The Primary Element in this case would be the lighting function, and the Light Lightness Server Model is used to access the lighting controls. The secondary element in this example is the sensor, where the occupancy sensor’s states can be accessed. Figure 4 shows a representation of both examples.

Every Element within a node has a unique address, known as a unicast address. This allows each Element to be addressed independently of other Elements within the same node.

Models

Models are used to define the functionality of a node – they bring together the concepts of states, transitions, bindings, and messages for an Element. Models are analogous to Services in regular Bluetooth devices. There are three types of Mesh Models – Client Models, Server Models, and Control models which implement both a Client and Server in a single model.

Server Model – A Server Model can have one or more states spanning one or more Elements. The Server Model defines messages a model may transmit and receive. It also defines the Element’s behaviors based on these messages. Said another way, Server Models expose the states of the Element that can be read or controlled by a Client. An example application of the Server Model is a sensor that exposes the sensor’s state or a light bulb that stores the current state of the light.

Client Model – A Client Model defines the set of messages to request and change the state of a Server. For example, an ON/OFF Switch (operating as a Client) can send a message to an ON/OFF Server to change the device’s state.

Control Model – An end application can use Server Models or Client Models, or both along with the control logic. Any combination of Server and Client Models results in a Control Model.

Model Hierarchy

Models can (and often do) extend the functionality of other models. That is, models can be hierarchical. For example, the ‘Light Lightness’ model extends the ‘Generic OnOff Server’ model and the ‘Generic Level Server’ model. What that means is that if you implement the Light Lightness model in an application, you get all the Light Lightness functionality plus all the Generic Level and Generic OnOff functionality. Models that do not extend other models are known as "root models".

States and Properties

States

Elements can be in various conditions; in Bluetooth Mesh, these conditions are stored in values called states. Each state is a value of a certain type contained within an element. In addition to the values, states have behaviors that are associated with that state. States are defined by the Bluetooth SIG.

For example, there is a state called ‘Generic OnOff’ which can have two values – ON or OFF. This is useful for devices like light bulbs or fan motors. The term ‘Generic’ is used to indicate that this state and its behaviors may be useful in different kinds of Mesh devices.

Properties

Properties also contain values relating to an element; however, unlike states, properties provide the context for interpreting states. For example, consider a device that wants to send a temperature state value. The temperature state may be "Present Indoor Ambient Temperature" or "Present Outdoor Ambient Temperature". In this case, a property would be used to provide the context for the temperature state value. Properties can be manufacturer properties, which are read-only or Admin properties, which allow read-write access.

State Transitions

State transitions may be instantaneous or may execute over a period called the transition time.

State Binding

Figure 4. Relationship Between Mesh Node, Elements, Models and States

States may be bound together such that a change in one state causes a change in the other. One state may be bound to multiple other states. For example, a light controlled by a dimmer switch will have one state called Generic OnOff and another called Generic Level to specify the brightness. If the light is in the ON state but is dimmed to the point that the Level becomes zero, then the OnOff state will transition to OFF. State binding is used in the Dimmable Light Bulb Code Example discussed later in this document.

State binding is defined by the models that contain the states in question. These can be found in the Bluetooth Mesh Specification.

Figure 4 illustrates the relationship between a Mesh node, elements, models and states.

Security and Privacy in BLE Mesh

Security and privacy are always a concern in wireless-connected devices. BLE Mesh incorporates several techniques to alleviate this concern. Table 3 details the security and privacy methods implemented in a BLE Mesh solution. To learn more about BLE security, refer to Bluetooth Mesh security overview at Bluetooth SIG website. To learn more about how they are implemented, refer to the BLE Mesh Networking Specification.

Table 3. Bluetooth Mesh Security and Privacy

Security/Privacy Feature What does it do?
Encryption and Authentication All Bluetooth mesh messages are encrypted and authenticated.
Separation of Concerns Network security, application security, and device security are addressed independently by means of separate keys for each. An AppKey is used to avoid any conflict of interest and differentiate one application type from another. For example, a sensor node cannot decode a message encrypted with the lighting AppKey. Each node possesses one or more NetKeys based on the network and subnets they are part of. The NetKey separates each network and subnet from all others. Each node has a unique DevKey that is used for provisioning and Configuration which separates it from all other devices.
Area Isolation A Bluetooth Mesh network can be divided into subnets, each cryptographically distinct and secure from the others. For example, each room in a hotel can be a subnet while the hotel is the complete network. Subnets allow guests from one room not to interfere with other rooms.
Key Refresh, Trashcan Attack Protection, and Node Removal Security keys can be changed during the life of the Bluetooth mesh network via a Key Refresh procedure. When a node is removed from the network, the Mesh network runs the key refresh procedure to change the keys on all other nodes. Once keys are refreshed, the (old) keys stored on the node that were removed have no value. This feature addresses security concerns if someone gains access to a device that was present earlier in a BLE network – this type of attached is known as a trashcan attack. .
Replay Attack Protection Bluetooth mesh security protects the network against replay attacks. Replay attacks are one of the most common attacks in which an eavesdropper listens to a message and then replays it with the bad intent. Imagine someone listens to a door unlock message and then replays it in the middle of the night to break into a house. BLE Mesh provides a mechanism to avoid replay attacks by adding a sequence number in each message. Messages with the same or lower sequence number as a previous message are automatically ignored.
Message Obfuscation Message obfuscation makes it difficult to track messages sent within the network and, as such, provides a privacy mechanism to make it difficult to track nodes.
Secure Device Provisioning BLE Mesh provides a secure method to add a device to the network.

Software Development Tools and Helper Applications

Cypress provides easy-to-use tools and Helper Applications to enable evaluation and development of Bluetooth Mesh products.

  1. ModusToolbox
  2. iOS helper application
  3. Android helper application
  4. Windows helper application

ModusToolBox

ModusToolbox is a free state-of-the-art software development ecosystem that includes the ModusToolbox IDE and Software Development Kits (SDKs) such as the WICED® BT SDK (hereafter referred to as the BT SDK) and the PSoC 6 SDK to develop applications for Cypress IoT products. ModusToolbox IDE is a multi-platform, Eclipse-based integrated development environment (IDE) used to create new applications, update application code, change middleware settings, and program/debug applications.

Using ModusToolbox IDE, you can enable and configure device resources and middleware libraries; write C source code; and program and debug the device. The IDE provides hooks for launching various tools provided by the BT SDK.

The BT SDK provides the core of the ModusToolbox software for creating Bluetooth LE, Classic, and Mesh applications with CYW20819 and EZ-BT modules based on it. It contains configuration tools, drivers, libraries, middleware, make files, as well as various utilities, and scripts.

Getting Started with ModusToolbox

Visit the ModusToolbox home page to download and install the latest version of ModusToolbox. Refer to the ModusToolbox Installation Guide document in the Documentation tab of ModusToolbox web page for information on installing the ModusToolbox software. After installing, launch ModusToolbox and navigate to the following items:

Installing BT SDK 1.2

To develop Mesh applications, BT SDK 1.2 or later must be used. Once ModusToolbox 1.1 is installed per the directions provided in ModusToolbox add the BT SDK 1.2 with following steps:

  1. Download BT SDK 1.2 from ModusToolbox BT SDK community page.
  2. Open ModusToolbox and go to Help > Update ModusToolbox SDKs… It will show a pop-up saying “Unable to find installable SDKs, check your Internet connection.” Click OK.
  3. The ‘Update ModusToolbox’ window appears. On the bottom left hand side, click ,Install Custom SDK.
  4. Browse to the downloaded SDK file and click Open. It will install the new SDK in ModusToolbox 1.1.

ModusToolbox IDE

Figure 5. ModusToolbox

The ModusToolbox IDE is based on the Eclipse IDE “Oxygen” version. It uses several plugins, including the Eclipse C/C++ Development Tools (CDT) plugin. Cypress provides an Eclipse Survival Guide, which provides tips and hints for how to use the ModusToolbox IDE.

The IDE contains Eclipse-standard menus and toolbars, plus various panes such as the Project Explorer, Code Editor, and Console as shown in Figure 5. One difference from the standard Eclipse IDE is the “ModusToolbox Perspective.” This perspective provides the Quick Panel, a News View, and adds tabs to the Project Explorer. In the IDE, the top-level entity that you ultimately program to a device is called an application. The application consists of one or more Eclipse projects. The IDE handles all dependencies between the projects automatically. It also provides hooks for launching various tools provided by the software development kits (SDKs). With the ModusToolbox IDE, you can:

  1. Create a new application based on a list of starter applications, filtered by kit or device, or browse the collection of code examples online.
  2. Configure device resources to build your hardware system design in the workspace.
  3. Add software components or middleware.
  4. Develop your application firmware.

For more detailed information on ModusToolbox and how to create an application, see the ModusToolbox IDE User Guide.

SDK for CYW20819

Figure 6. BT SDK API Reference

SDKs provide the core of the ModusToolbox software. SDKs make it easier to develop firmware for supported devices without the need to understand all the intricacies of the device resources. An SDK contains configuration tools, drivers, libraries, and middleware as well as various utilities, Makefiles, and scripts. CYW20819 and CYW20819-based module application development is enabled by the BT SDK within ModusToolbox. Important features of the BT SDK are listed below:

Bluetooth Mesh API documentation is available in Components > Bluetooth > BLE Mesh.

ModusToolbox Code Examples

ModusToolbox includes several code examples that are a great resource to understand the application code flow and to kickstart your application development. The following built-in code examples are compatible with the CYBT-213043-MESH EZ-BT Mesh Evaluation kit:

Many additional code and snip examples are available on GitHub. For more details on these additional code examples, refer to Additional Code Examples on GitHub.

Figure 7. Mesh Code Examples in ModusToolbox IDE

Figure 8. Searching for Online Code Examples in ModusToolbox IDE

You can either browse the collection of built-in starter applications during application set up through File > New > ModusToolbox IDE Application or browse the collection of code examples on Cypress’ GitHub repository. See Figure 7 and Figure 8 for details on selecting and searching for code examples. To learn how to create a project and program the EZ-BT Mesh evaluation board(s), refer to Mesh Code Examples and Programming the Evaluation Boards.

Additional Code Examples on GitHub

Cypress has many additional code and snip examples that are not included in the BT SDK installation. These additional code and snip examples can be accessed from the GitHub repository. To access these code examples and snip code, the developer can either directly click on the GitHub repository link or click the Search Online for Code Examples link provided in the Quick Panel section of the ModusToolbox IDE. For detailed instructions on how to obtain these examples and program the board, see Programing GitHub Examples.

Help topics and resources provided in the previous section cover how to create an application using ModusToolbox IDE. This section covers Bluetooth Mesh-specific settings available in ModusToolbox IDE that are needed when designing Bluetooth Mesh applications. To access these settings, right click on application’s mainapp folder in the Project Explorer window and select Change Application Settings.

Figure 9. Accessing Bluetooth Mesh Settings in ModusToolbox

Figure 10. Project Settings Window

After selecting the “Change Application Settings” above, the application settings window will appear as shown in Figure 9. The first four fields in this window are generic settings that apply to any CYW20819 application. The remaining fields are specific to BLE Mesh. All fields shown in Figure 10 are described in this section.

Based on the application requirement, each of these settings can and may be changed.

BT_DEVICE_ADDRESS: This field allows the developer to set either a default Bluetooth device address (random 6-byte address), or a predefined Static Bluetooth Address. Bluetooth Mesh uses a Random Private Address (RPA) and the Mesh application code takes care of this for you. Therefore, for Mesh applications, this field should remain unchanged.

UART: This field allows you to select the UART to download the application. For example, 'COM6' on Windows or '/dev/ttyWICED_HCI_UART0' on Linux or '/dev/tty.usbserial-000154' on macOS. By default, the SDK will auto detect the port. This field is especially useful when multiple boards are connected to a computer and a specific port needs to be programmed.

ENABLE_DEBUG: To enable hardware debugging, set this option to '1'. To learn more about SWD debugging in CYW20819 and related modules, refer to the Hardware Debugging for CYW207xx and CYW208xx guide available at Help > ModusToolbox General Documentation > ModusToolbox Documentation Index > Hardware Debugging for WICED devices.

MESH_MODELS_DEBUG_TRACES: This box, when checked, turns ON debug traces from the Mesh Models Library.

MESH_CORE_DEBUG_TRACES: This box, when checked, turns ON debug traces from the Mesh Core Library.

MESH_PROVISIONER_DEBUG_TRACES: This box, when checked, turns ON debug traces from the Mesh Provisioner Library.

REMOTE_PROVISION_SRV: This selection, when set to ‘1’, enables a device as a Remote Provisioning Server. It allows the provisioner to provision other nodes through this device if a remote node is not directly reachable to the Provisioner. This is an in-development feature and is not a part of the Bluetooth SIG Mesh 1.0 specification. This feature is not supported in the BT SDK version 1.2. Future versions of the BT SDK will enable this feature.

LOW_POWER_NODE: This selection, when set to ‘1’, enables the Low Power Node (LPN) feature on the device. Setting the value in this field to ‘1’ will define the LOW_POWER_NODE macro, which is used by the application to enable or disable low-power Mesh operation. Note that not all code examples that are provided in the BT SDK and on GitHub use the LOW_POWER_NODE application setting to enable low-power operation even though it is a global application setting. Also note that code examples that do use the LOW_POWER_NODE setting to enable low-power option do not enable it by default so you must enable it in the application settings if low-power operation is desired for those nodes

Helper Applications

Cypress provides Helper applications on Android, iOS, and Windows platforms that enable you to perform the following:

In addition to these features, the Windows application provides a trace window that displays details on various activities.

iOS Helper App

The iOS Helper app allows you to use an iOS phone or tablet to act as the Mesh Provisioning Client. Cypress provides a pre-built application that can directly be installed on an iOS device; in addition, it provides the source code to enable you to customize the application based on your end product and branding.

See iOS Helper App Installation.

Refer to Testing the Code Examples for instructions on how to use the Cypress iOS app and step-by-step details on testing the code examples covered in this application note.

Android Helper App

The Android Helper app allows you to use an Android device to act as the Mesh Provisioning Client. Cypress provides a pre-built application that can directly be installed on an device; in addition, it also provides the source code to enable you to customize the application based on your end product and branding.

OS requirements: Android version 7.1 or later

The Android helper application .apk file is available in the ModusToolbox installation directory at:

\ModusToolbox_1.1\libraries\bt_20819A1-1.0\components\BT-SDK\common\apps\snip\mesh\peerapps\Android\src\bin\MeshLightingController.apk

Source code is available at:

\ModusToolbox_1.1\libraries\bt_20819A1-1.0\components\BT-SDK\common\apps\snip\mesh\peerapps\Android\src\MeshApp

For the latest version of the Cypress Mesh Android app, download the source code from the GitHub repository.

To install the application on your Android device, copy the .apk file to your device. Then go to the device and browse to the .apk file from a file browser and tap to install it. Follow the on-screen instructions to install the application.

Refer to Using Android Helper App for instructions on using the Cypress Android app and step-by-step details on testing the example codes covered in this application note.

Windows Helper Applications

Cypress provides two different Windows Helper applications: MeshClient and ClientControlMesh.

Windows Helper applications are useful while developing Mesh applications as they provide ample details that can be useful while debugging applications.

The MeshClient and the ClientControlMesh applications provide a sample Windows implementation that show how to use interfaces exposed by Mesh libraries. The MeshClient requires Windows 10 or higher. MeshClient application uses the PC’s built-in Bluetooth radio, or an external Bluetooth dongle to communicate with the Bluetooth Mesh network.

The MeshClient application implements all layers of the Mesh stack. The ClientControlMesh application implements only the application layer. It uses the Mesh Models and Mesh Core libraries residing on an embedded device, requiring a Cypress device (Mesh or other evaluation board) connected to the PC to act as a Client for Mesh operations. Any of the Cypress devices that support Bluetooth Mesh can be used for this application irrespective of the device used in the Mesh nodes. The ClientControlMesh application can be used with any version of Windows operating system. The Mesh_provision_client snip example must be programmed on a Cypress device so that it can operate as a Client to a Mesh network in conjunction with the ClientControlMesh application. The Mesh_provision_client snip example can be downloaded from the GitHub repository. For detailed instructions on how to obtain snip examples and program the board, see Programing GitHub Examples.

See the MeshClient and ClientControlMesh App User Guide to find the application location, source code location, and instructions for using these apps. This user guide is also available as part of ModusToolbox installation and can be accessed from Help > ModusToolbox General Documentation > ModusToolbox Documentation Index.

Evaluation Kit

Figure 11. CYBT-213043-MESH Evaluation Board Top View

Figure 12. CYBT-213043-MESH Evaluation Board Bottom View

The EZ-BT Mesh Evaluation kit (CYBT-213043-MESH) enables the evaluation of the SIG Mesh functionality using the EZ-BT Bluetooth 5.0-qualified module CYBT-213043-02. The CYBT-213043-02s, EZ-BT module is an integrated, fully-certified, 12.0 mm x 16.61 mm x 1.70 mm, programmable dual-mode Bluetooth (BLE/BR/EDR) module with BLE Mesh support.

The CYBT-213043-02 module utilizes the Cypress CYW20819 silicon device. CYW20819 is an ultra-low-power and highly integrated dual-mode Bluetooth 5.0-qualified device. CYW20819’s low-power and integration capability addresses the requirements of both battery and wall-powered applications that require BLE Mesh, such as sensor nodes, locks, lighting, blind controllers, asset tracking, and many more smart home applications.

CYBT-213043-MESH kit contains the following:

Figure 11 shows the top view of a BLE Mesh evaluation board and calls out the main components and connections available on the board. All four boards provided in the CYBT-213043-MESH Evaluation Kit are identical and offer the same features and functionality. The BLE Mesh evaluation board can be powered via the USB connector located on the top side of the board or can be optionally powered by a CR2032 coin cell battery using the coin cell battery holder on the bottom of the evaluation boards (Figure 12).

CYBT-213043-MESH Board Components

Each of the four EZ-BT Mesh evaluation boards includes several elements as described below.

Active Devices

Figure 13. External Flash Schematics

Figure 14. PIR Motion Controller and PIR Sensor Schematicss

Switches and LEDs

Figure 15. User Defined Switch Schematics

Figure 16. RGB LED Schematics

Sensors

Figure 17. Thermistor Schematics

Figure 18. Ambient Light Sensor (ALS) Schematics

Connectors and Headers

Table 4. J5 Jumper Power Source Selection Options

J5 Jumper Configuration VDD Voltage Level
Short 1 & 2 USB Power (Default)
Short 2 & 3 Coin cell

Table 5.J8 Header Power Supply Connection Options

J8 Jumper Configuration VDD Voltage Level
Short 1 & 2 3.3 V (Default)
Short 2 & 3 3.6 V
Open 1 & 2 & 3 1.8 V

Programming the CYBT-213043-Mesh Evaluation Board

See Programming the Evaluation Boards for information on how to program the BLE Mesh evaluation boards.

Bluetooth Mesh Development Setup

Figure 19. Bluetooth Mesh Evaluation Setup With iOS/Android/Windows 10-based Devices with MeshClient Application

Figure 20. Bluetooth Mesh Evaluation Setup for Windows 10-based Devices Using ClientControlMesh Application

Figure 19 shows the hardware and software required for evaluating a Bluetooth Mesh design. CYBT-213043-MESH evaluation boards have a CYBT-213043-02 module that can talk to other Mesh boards/modules over an advertisement bearer and any of these boards can talk to a mobile phone running iOS or Android or even a PC running Windows 10. A Mesh device that talks directly to a PC or mobile phone is called a Proxy node. Communication between a Proxy node and a mobile phone/PC is over a GATT bearer; the Proxy then relays the information to/from the Mesh network over the Advertisement bearer. Each board needs to be programmed for the required Mesh functionality using ModusToolbox to work in a Mesh network.

If you are using the Windows ClientControlMesh application, one CYBT-213043-MESH board must be programmed as the Mesh Provisioning Client, because the ClientControlMesh Helper Application does not use the inbuilt Bluetooth communication on the Windows PC. Figure 20 shows the setup while using the ClientControlMesh application.

The Testing the Code Examples section of this application note will walk you through the steps on how create and test your Mesh network.

Architecture Overview

Cypress Bluetooth SIG Mesh Architecture Overview section describes the following details:

  1. Overview of the Cypress Mesh implementation. Jump to Cypress Mesh Implementation
  2. Understand the User Application Code Flow. Jump to User Application Code Flow

Within this section, the term “user application code” refers to the application code developed by you, the user, to define your specific Mesh application (i.e., this term does not refer to Cypress pre-built libraries). This code is analogous to the code that will be walked through in Mesh Code Examples.

If you are already familiar with the Cypress Mesh architecture, libraries, and application code flow, you can skip to Mesh Code Examples to walk through how to design Mesh applications.

For additional details on the Cypress Mesh Application library, see Understanding the Flow of the Cypress Mesh Application Library in the appendix.

Cypress Mesh Implementation

Figure 21. Cypress Bluetooth SIG Mesh Architecture

Figure 21 shows the Bluetooth SIG Mesh architecture implemented in the BT-SDK. . The Mesh Core library, Mesh Models library and Mesh App Library implementation does all the heavy lifting to be interoperable with a Bluetooth SIG Mesh network. The Mesh user application, as covered in code examples, just needs to define the Mesh configuration, hardware-specific configuration, and take necessary action when callbacks are received from Mesh app and Mesh model libraries. The Mesh Provisioner Library and Provisioner application help to implement a provisioner that creates a Mesh network, and provisions and configures new devices.

The following subsections provide details on each library.

Mesh User Application Code

The Mesh User Application code (code example or user application code) does not contain a Mesh-specific logic implementation. The Mesh User Application is the actual user application that defines the hardware actions and provides the methods for the application to exchange messages with other devices in the network. Cypress provides a number of Mesh code examples as part of BT-SDK as well as on GitHub for evaluating the Mesh functionality and to serve as a basis for your Mesh application development. Each code example provides a simple way to realize a specific functionality.

BT-SDK and GitHub code examples can be put in two different buckets:

Server or Client Mesh Code Examples

Server code examples leverage Mesh Server models. These code examples expose the states of the device to a Mesh Client. For example, the Dimmable Light code example uses the Light Lightness Server model and exposes the Server Model’s states to a Client. Based on messages received from the Client, the application code in the Dimmable Light example modifies the LED state. Client code examples leverage the Mesh Client models. Mesh Client code examples send commands to the network to change or read one or more Sever node’s states. For example, the Dimmer code example uses the Generic Level Client Model to change the level in the Dimmable Light example. The application code for the Dimmer example monitors the user button state and accordingly sends a set command message to the Mesh network.

Provisioner Mesh Code Example

The Mesh Provisioner application code example uses the Mesh Provisioner library to create a Mesh network, and to provision and configure Mesh nodes. To enable the features of this code example, connect the evaluation board programmed with the Provisioner Mesh code example to the PC. Use ClientControlMesh Windows application on the PC to create a Mesh network, provision Mesh devices, and control Mesh nodes.

Mesh Application Library

The Mesh Application library does not implement any core Mesh functionality. It can be considered as a subset of the application layer with a Mesh Application code example as its counterpart. This library implements state machines and event handlers for common BLE Mesh functionality. The Mesh Application library abstracts the complexity for the user application code. It provides callback functions to the Mesh Application code (user application) to allow the user to implement hardware-level and application-based functionality. The Mesh Application library takes care of initializing the Mesh Core libraries and registers appropriate callback functions. Most application settings and interactions with the Mesh Core library are taken care of by the Mesh Application library.

Mesh Models Library and Vendor Model Library

The Mesh Models Library contains the implementation of all standard models defined in the Mesh Models specification. The library keeps the information about device states and provides a logical interface for the Mesh Application and Mesh Application library to control or send the status information to the peer device. It translates the inputs from the Mesh Application and converts them into appropriate Mesh messages. The Mesh Models library receives, parses, and validates the messages received over the air and sends appropriate events to the Mesh application. The developer has an option to provide vendor-specific models not defined by the Mesh Models specification. In that case, Vendor-Specific Models will access the Mesh Core library interface directly. The interface between the application and the Mesh Vendor Model library is implementation-specific.

Mesh Provisioner Library

The Mesh Provisioner library contains the implementation of a provisioner as defined by the BLE Mesh Networking Specification. The Mesh Provisioner application code examples access the Mesh Provisioner library to create a new network, and to provision and configure Mesh devices.

Mesh Core Library

The Mesh Core library implements the core Mesh functionality from the Bluetooth Mesh profile as defined in the BLE Mesh Networking Specification and provides communication between devices in a Bluetooth Mesh network. The Provisioner assigns the device address and provides the security keys to the device. On the device side, everything is managed by the Mesh Core library. When the Mesh application code receives a callback to perform an action, the message is already validated to have the required permissions and the data is already decrypted by the Mesh Core library. Similarly, when the Mesh application needs to send the data out, the Mesh Core library encrypts the message with the keys provided during provisioning and sends it over the Bluetooth interface.

User Application Code Flow

The Mesh Application Library takes care of the interaction with the Mesh Models library and the Mesh Core library. The Mesh Application library sends relevant events and callback functions to the user application code to implement the application- and hardware-specific functionality. Additional details on the Mesh Application Library can be found in Understanding the Flow of the Cypress Mesh Application Library.

The user application code is a specific implementation for every application for the following reasons:

Figure 22. Typical Mesh User Application Code Flow

Before we get into the details of the steps that are part of developing the Mesh user application code, let us get familiar with the configuration variables that are needed for a Mesh device. Figure 23 illustrates how the different variables interact with each other to configure the mesh device. The following section provides details regarding each parameter that is part of Figure 23.

Figure 23. Typical Mesh Device Configuration Variables

Step 1: Define Mesh Device Configuration

The device configuration structure for the Mesh device, wiced_bt_mesh_core_config_t, defines the following parameters/features:

Mesh Company ID

The Bluetooth SIG defined company identifier should be assigned to this field. In this case, the Cypress company identifier is assigned (0x0131).

Mesh PID

This field is a vendor-assigned product identifier, which is 16 bits in length. Typically, each product group will have a unique value assigned to this field; for example, in the code examples, all Dimmable Light devices are assigned with a value “0x311F” and all Dimmer Switch devices are assigned with a value “0x3005”.

Mesh VID

This field is a vendor-assigned product version identifier, which is 16 bits in length. For all the code examples from Cypress, this value is defined as “0x0001”.

Maximum Size of Replay Protection List

This is determined by the maximum number of Mesh devices in a network which can send messages to this device. A value of ‘8’ is assigned by default for all the code examples which are part of the BT SDK and GitHub. The maximum size of the replay protection list is determined by the amount of available RAM space in your design. We have configured a value of ‘8’ corresponding to a typical use case (e.g., a dimmable light bulb node controlled by 3-5 mobile phones, and 2-3 dimmer/sensor nodes).

If the maximum number of devices is exceeded, then the node will ignore messages from Clients that are not already contained in the list of 8, until the list is cleared. If you have reached the maximum number of devices in the Replay Protection List, the node will automatically initiate an IV (Initialization Vector) index update procedure, which clears Replay Protection List, updates the index and allows new devices to be added to the list. An IV index update procedure can only occur once in a 96-hour period.

Features Supported by the Mesh Device

These include Friend, Relay, Proxy server, Low Power Node, Bearer support configuration (Advertisement Bearer or GATT Bearer). You can enable specific features by modifying appropriate bits in the ‘features’ parameters as required. For example, use the following to enable the Friend and relay feature (if required):

.features = WICED_BT_MESH_CORE_FEATURE_BIT_FRIEND | WICED_BT_MESH_CORE_FEATURE_BIT_RELAY

Friend Node and LPN Configuration

Parameters for the Friend node and LPN are defined in the structures wiced_bt_mesh_core_config_t.friend_cfg and wiced_bt_mesh_core_config_t.low_power. These structures are described in wiced_bt_mesh_core_config_t.friend_cfg and wiced_bt_mesh_core_config_t.low_power.

wiced_bt_mesh_core_config_t.friend_cfg

The wiced_bt_mesh_core_config_t.friend_cfg parameters define the supported Friend features when a Mesh device is configured as a Friend node. These include the following:

Figure 24. LPN and Friend Node Communication Timing (Bluetooth SIG, 2019)

wiced_bt_mesh_core_config_t.low_power

The wiced_bt_mesh_core_config_t.low_power parameters define the timing and cache size required by the LPN. This includes the following:

Figure 25. Poll Timeout and Friendship Termination (Bluetooth SIG, 2019)

To understand the parameters of Friend node and LPN, consider how an LPN establishes friendship with a Friend node. The LPN node sends the RSSI Factor and RECEIVE WINDOW FACTOR to the adjacent Friend nodes as part of the Friend Request. Friend nodes receive the Friend Request and calculate a local delay using following formula:

Local Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI

ReceiveWindowFactor is a number from the Friend Request message sent by LPN.

ReceiveWindow is the value to be sent in the corresponding Friend Offer message by the Friend Node.

RSSIFactor is a value from the Friend Request message sent by LPN.

RSSI is the received signal strength of the received Friend Request message (sent by LPN) at the Friend node.

Potential Friend devices who receive the Friend Request calculate their Local Delay based on the received parameters and its own Receive Window parameter. If the calculated Local Delay is greater than 100, then the Friend Offer message is sent after the calculated Local Delay value in milliseconds. If the calculated Local Delay is less than 100, the Friend Offer message is sent after 100 milliseconds.

This means that the LPN receives Friend offers quicker from nodes that more closely match the LPN requirements, reducing the power consumed by the LPN when initially searching for a Friend node.

Friend and Low-Power Configuration Example

Figure 26. LPN and Friend Node Friendship Establishment Flow (Bluetooth SIG, 2019)

Consider the following the examples:

Case 1:

Consider an LPN and two Friend nodes with the following parameters:

Table 6. Case 1 Example of LPN Friendship Establishment

LPN Friend 1 Friend 2
RSSI Factor 2
Receive Window Factor 2
Receive Window 200 300
Measured RSSI by Friend 90 dBm 40 dBm

In this case:

The LPN will receive a Friend offer from Friend 1 and Friend 2 after 220 ms and 520 ms respectively.

Case 2:

If we have one LPN and two Friend nodes with below parameters

Table 7. Case 2 Example of LPN Friendship Establishment

LPN Friend 1 Friend 2
RSSI Factor 2
Receive Window Factor 2
Receive Window 200 100
Measured RSSI by Friend 90 dBm 40 dBm

In this case:

The LPN will receive a Friend offer from Friend 1 and Friend 2 after 220 ms and 120 ms respectively.

This means that the LPN receives Friend offers quicker from nodes that match the LPN requirements, reducing the power consumed by the LPN when initially searching for a Friend Node.

Figure 26 shows the Friendship establishment flow.

Code 1: Configuration of wiced_bt_mesh_core_config_t Structure

wiced_bt_mesh_core_config_t  mesh_config =
{
    .company_id         = MESH_COMPANY_ID_CYPRESS, // Company identifier assigned by the Bluetooth SIG
    .product_id         = MESH_PID,                // Vendor-assigned product identifier
    .vendor_id          = MESH_VID,                // Vendor-assigned product version identifier
    .replay_cache_size  = MESH_CACHE_REPLAY_SIZE,  // Number of replay protection entries, i.e. maximum number of mesh devices that can send application messages to this device.
    .features           = WICED_BT_MESH_CORE_FEATURE_BIT_FRIEND 
    | WICED_BT_MESH_CORE_FEATURE_BIT_RELAY | WICED_BT_MESH_CORE_FEATURE_BIT_GATT_PROXY_SERVER,   
    // In Friend mode support friend, relay
    .friend_cfg         =                         // Configuration of the Friend Feature(Receive Window in Ms, messages cache)
    {
        .receive_window        = 200,            // Receive Window value in milliseconds supported by the Friend node.
        .cache_buf_len         = 300             // Length of the buffer for the cache
    },
    .low_power          =                       // Configuration of the Low Power Feature
    {
        .rssi_factor           = 0,             // contribution of the RSSI measured by the Friend node used in Friend Offer Delay calculations.
        .receive_window_factor = 0,            // contribution of the supported Receive Window used in Friend Offer Delay calculations.
        .min_cache_size_log    = 0,           // minimum number of messages that the Friend node can store in its Friend Cache.
        .receive_delay         = 0,          // Receive delay in 1 ms units to be requested by the Low Power Node.
        .poll_timeout          = 0          // Poll timeout in 100ms units to be requested by the Low Power Node.
    },
    .gatt_client_only          = WICED_FALSE,// Can connect to mesh over GATT or ADV
    .elements_num  = (uint8_t)(sizeof(mesh_elements) / sizeof(mesh_elements[0])), 
    // number of elements on this device
    .elements      = mesh_elements        // Array of elements for this device
};

Code 1 shows a completed wiced_bt_mesh_core_config_t structure.

Step 2: Define Mesh Element Configuration

The Mesh element configuration structure, wiced_bt_mesh_core_config_element_t, defines the following parameters for a Mesh device. Because Mesh devices can contain more than one element, this structure is an array with one entry per element in the device.

Code 2. Configuring Element Property Structure

wiced_bt_mesh_core_config_property_t mesh_element1_properties[] =
{
    {
        .id          = WICED_BT_MESH_PROPERTY_DEVICE_FIRMWARE_REVISION,
        .type        = WICED_BT_MESH_PROPERTY_TYPE_USER,
        .user_access = WICED_BT_MESH_PROPERTY_ID_READABLE,
        .max_len     = WICED_BT_MESH_PROPERTY_LEN_DEVICE_FIRMWARE_REVISION,
        .value       = mesh_prop_fw_version
    },
};

Code 3. Element Initialization in the BLE_Mesh_LightDimmable Code Example

wiced_bt_mesh_core_config_element_t mesh_elements[] =
{
    {
     .location = MESH_ELEM_LOC_MAIN,                                 // location description as defined in the GATT Bluetooth Namespace Descriptors 
                                                                           section of the Bluetooth SIG Assigned Numbers
     .default_transition_time = MESH_DEFAULT_TRANSITION_TIME_IN_MS,  // Default transition time for models of the element in milliseconds
     .onpowerup_state = WICED_BT_MESH_ON_POWER_UP_STATE_RESTORE,     // Default element behavior on power up
     .default_level = 0,                                             // Default value of the variable controlled on this element 
                                                                       (for example power,      
                                                                      lightness, temperature, hue...)
    .range_min = 1,                                                 // Minimum value of the variable controlled on this element (for example power, 
                                                                       lightness, temperature, hue...)
    .range_max = 0xffff,                                            // Maximum value of the variable controlled on this element (for example power, 
                                                                       lightness, temperature, hue...)
    .move_rollover = 0,                                             // If true when level gets to range_max during move operation, it switches to 
                                                                           min, otherwise move stops.
    .properties_num = MESH_APP_NUM_PROPERTIES,                      // Number of properties in the array models
    .sensors_num = 0,                                               // Number of sensors in the sensor array
    .sensors = NULL,                                                // Array of sensors of that element
    .models_num = MESH_APP_NUM_MODELS,                              // Number of models in the array models
    .models = mesh_element1_models,                                 // Array of models located in that element. Model data is defined by structure 
                                                                       wiced_bt_mesh_core_config_model_t
    },
};

In the light_dimmable code example, the firmware version is defined as a user property for the primary element as shown in Code 2.

Code 3 shows the BLE_Mesh_LightDimmable code example element initialization/assignment. This example contains properties and models but no sensors.

Step 3: Define Application Callback Functions

Hardware-specific initialization and application-specific callbacks are defined in the wiced_bt_mesh_app_func_table_t structure to enable the Mesh application library to route appropriate callbacks to the user application code. Details of the functions defined in the wiced_bt_mesh_app_func_table_t structure are provided in Table 8.

Table 8. Application Function Definitions

Application Callback Function Comments
wiced_bt_mesh_app_init_t This function is called in the mesh_application_init() function in mesh_application.c. The user application must initialize Mesh Server or Client Models in this function. You can also initialize any custom features based on application needs like PWM, Timers, etc. This is a mandatory callback for user application code. Every code example has this callback function defined in the wiced_bt_mesh_app_func_table_t structure and uses the name mesh_app_init.
wiced_bt_mesh_app_hardware_init_t This function is called in the APPLICATION_START() function in mesh_application.c. Implementation of this function in the user application code is optional. Default hardware configuration for buttons, LEDs, and UART are initialized per the Mesh evaluation board if the user application code does not define a callback function for hardware initialization. The default behavior for the user button on the Mesh Evaluation board is a factory reset so if this callback is not specified, pressing/releasing the user button will remove all provisioning information from the device.
wiced_bt_mesh_app_gatt_conn_status_t This function is called in the mesh_gatts_callback() function in mesh_app_gatt.c. Implementation of this function in the application is optional. This function allows the application to be notified of a change in the Bluetooth GATT connection status. This function can be used to perform a custom action if required (e.g., turn ON or turn OFF an LED) for a GATT connect/disconnect event.
wiced_bt_mesh_app_attention_t This function is registered as a callback function with the Mesh Core in the wiced_bt_mesh_core_init() function in mesh_application.c. This callback function is triggered by the Mesh Core Library for the developer to implement logic that can alert the user (e.g., provide the user with a visual indication of which device is being provisioned). If this function is implemented, it should start a periodic seconds attention timer. For example, in the Dimmable Light bulb code example, the LED state is toggled (ON/OFF) every second in the callback function attention_timer_cb until the attention timer expires.
wiced_bt_mesh_app_notify_period_set_t This function is called in the mesh_publication_callback() function in mesh_application.c. This function is used to change the timing for periodic notifications (i.e., publications). Implementation of this function in the user application code is required for Sensor Models as the publish period may need to be modified based on the fast_cadence_period_divisor setting.
wiced_bt_mesh_app_proc_rx_cmd_t This function is called in the mesh_application_proc_rx_cmd() function in mesh_app_hci.c. Implementation of this function in the user application code is optional. If defined in the user application code, this function is called when an HCI UART command is received from the external host. This function is relevant in the case of a hosted MCU implementation; it is not applicable for a standalone chip implementation.
wiced_bt_mesh_app_lpn_sleep_t This function is called in the WICED_BT_MESH_CORE_STATE_LPN_SLEEP event of the mesh_state_change_cb function in mesh_application.c. Implementation of this function in the user application code is mandatory for Mesh devices which support the LPN (Low Power Node) feature. In this function, the user application can put the Mesh device in to the lowest power state by calling wiced_sleep_enter_hid_off. The parameter passed is the maximum time that the device may be put to sleep. It is up to the user application to decide whether to not sleep, sleep for a reduced amount of time, or sleep for the maximum allowed time based on tis own requirements.
wiced_bt_mesh_app_factory_reset_t This function is called in the mesh_application_factor_reset() function in mesh_application.c. Default code in mesh_application.c file takes care of initializing the Mesh Core on a factory reset operation. Implementation of this callback function in the user application code is optional. The code placed in this function is executed before the Mesh Core rest code. For example, a Mesh code example can implement this function to delete data stored in NVRAM during a factory reset.

Step 4: Implement Application Callback Functions

The callback functions defined in Step 3 are implemented in this step. The following are examples of typical features and functions that are implemented in the user application code.

Step 5: Implement the Mesh Model Callback Functions

During initialization, a callback function is registered for each model to handle the received messages and perform an appropriate action. For example, in the case of a Dimmable Light bulb code example mesh_app_message_handler is registered during Model initialization for the Light Lightness Server Model. The Mesh Models library will trigger a callback to the function mesh_app_message_handler if it receives data for the registered Model. The User application code receives lightness/level information and accordingly control the level (brightness) of the LED. See Step5 of the Dimmable Light Bulb Code Example for further details.

The user application code can also implement design-specific application functions to achieve the required functionality in this step. For example, in a Dimmer Switch application custom logic is implemented to handle the button press events.

If a given model does not require a callback function (i.e., it doesn’t require the user application code to take any action for received messages), the callback can be specified as NULL in the Model initialization function.

Mesh Code Examples

The code examples described in this application note are designed for specific applications, such as a Dimmable Light Bulb and Dimmer Switch. General code examples demonstrating each Mesh Model can be found in GitHub. In this section, we will step through two use cases which implement a variety of Mesh features and functionalities. The three use cases that will be covered in this section are shown below:

1.Use Case #1: Dimmer Switch Controlling Three Dimmable Light Bulbs using the following code examples:

2.Use Case #2: Low-Power ON/OFF Server with Three Dimmable Light Bulbs

Prerequisites

Before you get started with the implementation, ensure that you have the following software and hardware:

Use Case #1: Dimmer Switch Controlling Three Dimmable Light Bulbs

Figure 27. Use Case 1: Dimmer Switch with Three Dimmable Light Bulbs)

There are two example projects associated with Use Case #1, BLE_Mesh_Dimmer (Dimmer Switch) and BLE_Mesh_LightDimmable (Dimmable Light Bulb). These code examples are detailed in Dimmer Switch and Dimmable Light Bulb Code Example .

In this use case, a button press on the Dimmer Switch device will initiate a command that controls the level and ON/OFF state of the LED on the Dimmable Light Bulb nodes. The LED on the Dimmable Light Bulb nodes can also be controlled using the Mesh Helper applications (Android/iOS or Windows). Figure 27 summarizes the functions and assignments for each of the four Mesh evaluation boards used in this example.

Dimmer Switch Code Example

Dimmer Switch Characteristics

BLE_Mesh_Dimmer Code Example

Code 4. Dimmer Switch Mesh Core Configuration Structure

wiced_bt_mesh_core_config_t  mesh_config =
{
    .company_id         = MESH_COMPANY_ID_CYPRESS,                  // Company identifier assigned by the Bluetooth SIG
    .product_id         = MESH_PID,                                 // Vendor-assigned product identifier
    .vendor_id          = MESH_VID,                                 // Vendor-assigned product version identifier
    .firmware_id        = MESH_FWID,                                // Vendor-assigned firmware version identifier
    .replay_cache_size  = MESH_CACHE_REPLAY_SIZE,                   // Number of replay protection entries, i.e. maximum number of mesh devices that                                                     
                                                                       can send application messages to this device.
#if defined(LOW_POWER_NODE) && (LOW_POWER_NODE == 1)
    .features           = WICED_BT_MESH_CORE_FEATURE_BIT_LOW_POWER, // A bit field indicating the device features. In Low Power mode no Relay, no Proxy and no Friend
    .friend_cfg         =                                           // Empty Configuration of the Friend Feature
    {
        .receive_window = 0,                                        // Receive Window value in milliseconds supported by the Friend node.
        .cache_buf_len  = 0                                         // Length of the buffer for the cache
    },
    .low_power          =                                           // Configuration of the Low Power Feature
    {
        .rssi_factor           = 2,                                 // contribution of the RSSI measured by the Friend node used in Friend Offer Delay                                                                        
                                                                       calculations.
        .receive_window_factor = 2,                                 // contribution of the supported Receive Window used in Friend Offer Delay calculations.
        .min_cache_size_log    = 3,                                 // minimum number of messages that the Friend node can store in its Friend Cache.
        .receive_delay         = 100,                               // Receive delay in 1ms units to be requested by the Low Power Node.
        .poll_timeout          = 36000                              // Poll timeout in 100ms units to be requested by the Low Power Node.
    },
#else
    .features           = 0,                                        // no, support for proxy, friend, or relay
    .friend_cfg         =                                           // Empty Configuration of the Friend Feature
    {
        .receive_window         = 0,                                // Receive Window value in milliseconds supported by the Friend node.
        .cache_buf_len          = 0                                 // Length of the buffer for the cache
    },
    .low_power          =                                           // Configuration of the Low Power Feature
    {
        .rssi_factor           = 0,                                 // contribution of the RSSI measured by the Friend node used in Friend Offer Delay 
                                                                       calculations.
        .receive_window_factor = 0,                                 // contribution of the supported Receive Window used in Friend Offer Delay calculations.
        .min_cache_size_log    = 0,                                 // minimum number of messages that the Friend node can store in its Friend Cache.
        .receive_delay         = 0,                                 // Receive delay in 1 ms units to be requested by the Low Power Node.
        .poll_timeout          = 0                                  // Poll timeout in 100ms units to be requested by the Low Power Node.
    },
#endif
    .gatt_client_only          = WICED_FALSE,                       // Can connect to mesh over GATT or ADV
    .elements_num  = (uint8_t)(sizeof(mesh_elements) / sizeof(mesh_elements[0])),   // number of elements on this device
    .elements      = mesh_elements                                  // Array of elements for this device
};

This section describes the five key steps required to implement this code example. These steps are already implemented in the provided code example and are described here for learning purposes.

Step 1: In this step, the Mesh Core configuration structure (wiced_bt_mesh_config_t) parameters are configured. The Dimmer Switch Core Configuration Structure used for this example code is shown in Code 4.

Each parameter in this structure is explained in Mesh Device Configuration. Key items configured in this structure for the Dimmer Switch code example are as follows:

The LOW_POWER_NODE macro is not enabled for the Dimmer Switch application as this device is generally connected to a main power supply. Enable the LOW_POWER_NODE macro in the application settings if the Dimmer Switch device is battery powered.

.features = WICED_BT_MESH_CORE_FEATURE_BIT_FRIEND | WICED_BT_MESH_CORE_FEATURE_BIT_RELAY

Code 5. Dimmer Switch Mesh Core Element Configuration Structure

wiced_bt_mesh_core_config_element_t mesh_elements[] =
{
    {
        .location = MESH_ELEM_LOC_MAIN,                                 // location description as defined in the GATT Bluetooth Namespace Descriptors section of 
                                                                           the Bluetooth SIG Assigned Numbers
        .default_transition_time = MESH_DEFAULT_TRANSITION_TIME_IN_MS,  // Default transition time for models of the element in milliseconds
        .onpowerup_state = WICED_BT_MESH_ON_POWER_UP_STATE_RESTORE,     // Default element behavior on power up
        .default_level = 0,                                             // Default value of the variable controlled on this element (for example power, lightness,            
                                                                           temperature, hue...)
        .range_min = 1,                                                 // Minimum value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .range_max = 0xffff,                                            // Maximum value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .move_rollover = 0,                                             // If true when level gets to range_max during move operation, it switches to min, 
                                                                           otherwise move stops.
        .properties_num = 0,                                            // Number of properties in the array models
        .properties = NULL,                                             // Array of properties in the element.
        .sensors_num = 0,                                               // Number of sensors in the sensor array
        .sensors = NULL,                                                // Array of sensors of that element
        .models_num = MESH_APP_NUM_MODELS,                              // Number of models in the array models
        .models = mesh_element1_models,                                 // Array of models located in that element. Model data is defined by structure 
                                                                           wiced_bt_mesh_core_config_model_t
    },
};

wiced_bt_mesh_core_config_model_t   mesh_element1_models[] =
{
    WICED_BT_MESH_DEVICE,
    WICED_BT_MESH_MODEL_LEVEL_CLIENT,
};

Step 2: In this step, the Mesh Core Element configuration structure (wiced_bt_mesh_core_config_element_t) parameters are configured. The Mesh Core Element Configuration Structure used for the Dimmer Switch is shown in Code 5. This example contains one element.

Each parameter in this structure is explained in Mesh Element Configuration. Key parameters configured in this structure for the Dimmer Switch code example are described below:

For example, the model implemented in the Dimmer Switch code example can also control the following server models:

WICED_BT_MESH_MODEL_LIGHT_LIGHTNESS_SERVER,WICED_BT_MESH_MODEL_LIGHT_CTL_SERVER, WICED_BT_MESH_MODEL_LIGHT_HSL_SERVER, etc.

Step 3: This step registers the application callback functions for the code example.

The Mesh application initialization and hardware initialization callback functions are defined in the wiced_bt_mesh_app_func_table_t structure. The Mesh Core performs default actions as defined in the mesh_application.c file for the items that do not have any callback function registered in the function table.

Code 6. Dimmer Switch Application Function Definitions

  wiced_bt_mesh_app_func_table_t wiced_bt_mesh_app_func_table =
{
    mesh_app_init,          // application initialization
    button_hardware_init,   // hardware initialization
    NULL,                   // GATT connection status
    NULL,                   // attention processing
    NULL,                   // notify period set
    NULL,                   // WICED HCI command
    NULL,                   // LPN sleep
    NULL                    // factory reset
};

For example, the Dimmer Switch application project will not receive any callback on a GATT connection or disconnection. Because there is no callback function defined in this case, the Dimmer Switch application will not be able to process any custom actions (e.g., turn ON or turn OFF a LED) on a GATT connection or disconnection. A callback function can be added to this structure to enable the user to perform a custom action if desired.

The application function definitions that are used for the Dimmer Switch code example are shown in Code 6.

Code 7. mesh_app_init() Function

Void mesh_app_init(wiced_bool_t is_provisioned)
{
#if 0
    extern uint8_t wiced_bt_mesh_model_trace_enabled;
    wiced_bt_mesh_model_trace_enabled = WICED_TRUE;
#endif
  wiced_bt_cfg_settings.device_name = (uint8_t *)"Dimmer";
    wiced_bt_cfg_settings.gatt_cfg.appearance = APPEARANCE_CONTROL_DEVICE_SLIDER;

// Adv Data is fixed. Spec allows to put URI, Name, Appearance and Tx Power in the Scan Response Data.
    if (!is_provisioned)
    {
        wiced_bt_ble_advert_elem_t  adv_elem[3];
        uint8_t                     buf[2];
        uint8_t                     num_elem = 0;

        adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_NAME_COMPLETE;
        adv_elem[num_elem].len         = (uint16_t)strlen((const char*)wiced_bt_cfg_settings.device_name);
        adv_elem[num_elem].p_data      = wiced_bt_cfg_settings.device_name;
        num_elem++;

        adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_APPEARANCE;
        adv_elem[num_elem].len         = 2;
        buf[0]                         = (uint8_t)wiced_bt_cfg_settings.gatt_cfg.appearance;
        buf[1]                         = (uint8_t)(wiced_bt_cfg_settings.gatt_cfg.appearance >> 8);
        adv_elem[num_elem].p_data      = buf;
        num_elem++;

        wiced_bt_mesh_set_raw_scan_response_data(num_elem, adv_elem);
    }
    button_control_init();
    wiced_bt_mesh_model_level_client_init(MESH_LEVEL_CLIENT_ELEMENT_INDEX, mesh_app_message_handler, is_provisioned);
}

Step 4: This step implements the application callback functions. There are two application callback functions defined for the BLE_Mesh_Dimmer code example, mesh_app_init() and button_hardware_init(). Each is described below.

1.mesh_app_init()

In this function shown in Code 7, the following actions are performed:

wiced_bt_cfg_settings.device_name = (uint8_t *)"Dimmer";

wiced_bt_cfg_settings.gatt_cfg.appearance = APPEARANCE_CONTROL_DEVICE_SLIDER;

2.button_hardware_init()

Code 8. button_hardware_init() Function

void button_hardware_init(void)
{
    /* Configure buttons available on the platform */
#if defined(CYW20706A2)
    wiced_hal_gpio_configure_pin(WICED_GPIO_BUTTON, WICED_GPIO_BUTTON_SETTINGS(GPIO_EN_INT_BOTH_EDGE), WICED_GPIO_BUTTON_DEFAULT_STATE);
    wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_BUTTON, button_interrupt_handler, NULL);
#elif (defined(CYW20735B0) || defined(CYW20719B0) || defined(CYW20721B0))
    wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_PIN_BUTTON, button_interrupt_handler, NULL);
    wiced_hal_gpio_configure_pin(WICED_GPIO_PIN_BUTTON, WICED_GPIO_BUTTON_SETTINGS, GPIO_PIN_OUTPUT_LOW);
#else
    wiced_platform_register_button_callback(WICED_PLATFORM_BUTTON_1, button_interrupt_handler, NULL, GPIO_EN_INT_BOTH_EDGE);
#endif
}

Code 9. button_interrupt_handler() Function

/* Process interrupts from the button */
void button_interrupt_handler(void* user_data, uint8_t pin)
{
    uint32_t value = wiced_hal_gpio_get_pin_input_status(pin);
    uint32_t current_time = wiced_bt_mesh_core_get_tick_count();
    uint32_t button_pushed_duration;

    if (value == button_previous_value)
    {
        WICED_BT_TRACE("interrupt_handler: duplicate pin:%d value:%d current_time:%d\n", pin, value, current_time);
        return;
    }
    button_previous_value = value;

    WICED_BT_TRACE("interrupt_handler: pin:%d value:%d current_time:%d\n", pin, value, current_time);

    if (value == platform_button[WICED_PLATFORM_BUTTON_1].button_pressed_value)
    {
        button_pushed_time = current_time;

        // if button is not released within 500ms, we will start sending move events
        wiced_start_timer(&button_timer, 500);
        return;
    }
    wiced_stop_timer(&button_timer);

    // button is released
    button_pushed_duration = current_time - button_pushed_time;
    if (button_pushed_duration < 500)
    {
        button_level_moving = WICED_FALSE;

        if (button_step == 0)
            button_step = NUM_STEPS - 1;
        else if (button_step == NUM_STEPS - 1)
            button_step = 0;
        else
            button_step = (button_direction ? NUM_STEPS - 1 : 0);
        button_set_level(WICED_TRUE, WICED_TRUE);
        return;
    }
    else if (button_pushed_duration < 15000)
    {
        // we were moving the level and button is released.
        // set message with ack
        if ((button_step != NUM_STEPS - 1) && (button_step != 0))
            button_set_level(WICED_FALSE, WICED_TRUE);
        return;
    }
    // More than 15 seconds means factory reset
    mesh_application_factory_reset();
}

Code 8 shows the button_hardware_init() function. In this function, the User Button of the evaluation board is configured with an interrupt, and an interrupt callback function is registered. In this case, the User Button number (WICED_PLATFORM_BUTTON_1), User Button configuration (GPIO_EN_INT_BOTH_EDGE), and interrupt callback function (button_interrupt_handler) are passed as the parameters to wiced_platform_register_button_callback. The interrupt callback function, button_interrupt_handler, is triggered when the User Button is pressed or released.

Functions related to the User Button handling are implemented in button_control.c. The callback function button_interrupt_handler handles the User Button interrupts and implements the logic shown in Code 9.The function button_set_level is called in the button_interrupt_handler. The wiced_bt_mesh_model_level_client_set() API is called in the button_set_level function to publish Mesh messages. Code 10 shows the button_set_level() function, which is called by the button_interrupt_handler() function.

Code 10. button_set_level() Function

void button_set_level(wiced_bool_t is_instant, wiced_bool_t is_final)
{
    wiced_bt_mesh_level_set_level_t set_data;

    set_data.level = button_level_step[button_step];
    set_data.transition_time = is_instant ? 100 : 500;
    set_data.delay = 0;

    WICED_BT_TRACE("Set level:%d transition time:%d final:%d\n", set_data.level, set_data.transition_time, is_final);

    wiced_bt_mesh_model_level_client_set(0, is_final, &set_data);
}

Code 11. mesh_app_message_handler() Callback Function

Void mesh_app_message_handler(uint16_t event, wiced_bt_mesh_event_t *p_event, wiced_bt_mesh_level_status_data_t *p_data)
{
    WICED_BT_TRACE(level clt msg:%d\n, event);

    switch (event)
    {
    case WICED_BT_MESH_TX_COMPLETE:
        WICED_BT_TRACE(tx complete status:%d\n, p_event->tx_status);
        break;

    case WICED_BT_MESH_LEVEL_STATUS:
        WICED_BT_TRACE(level present:%d target:%d remaining time:%d\n, p_data->present_level, p_data->target_level, p_data->remaining_time);
        break;

    default:
        WICED_BT_TRACE(unknown\n);
        break;
    }
    wiced_bt_mesh_release_event(p_event);
}

Step 5: This step implements the Mesh message Callback functions.

Because the Dimmer Switch is a client device, the purpose of the defined callback function is not to process and take any action, but to confirm that messages are sent into the network. The mesh_app_message_handler callback function registered during initialization in the Dimmer Switch application will receive callbacks from the Mesh Models Library, which provides information as to the current Light Level Status of the Dimmer Switch and the status of any Mesh network messages being sent from the Dimmer Switch.

Dimmable Light Bulb Code Example

Dimmable Light Bulb Characteristics

Dimmable Light Bulb (Mesh Server): BLE_Mesh_LightDimmable

Code 12. Dimmable Light Mesh Core Configuration Structure

wiced_bt_mesh_core_config_t  mesh_config =
{
    .company_id         = MESH_COMPANY_ID_CYPRESS,                  // Company identifier assigned by the Bluetooth SIG
    .product_id         = MESH_PID,                                 // Vendor-assigned product identifier
    .vendor_id          = MESH_VID,                                 // Vendor-assigned product version identifier
    .replay_cache_size  = MESH_CACHE_REPLAY_SIZE,                   // Number of replay protection entries, i.e. maximum number of mesh devices that can send 
                                                                       application messages to this device.
    .features           = WICED_BT_MESH_CORE_FEATURE_BIT_FRIEND | WICED_BT_MESH_CORE_FEATURE_BIT_RELAY | WICED_BT_MESH_CORE_FEATURE_BIT_GATT_PROXY_SERVER,   // In 
                                                                       Friend mode support friend, relay
    .friend_cfg         =                                           // Configuration of the Friend Feature(Receive Window in Ms, messages cache)
    {
        .receive_window        = 200,                               // Receive Window value in milliseconds supported by the Friend node.
        .cache_buf_len         = 300                                // Length of the buffer for the cache
    },
    .low_power          =                                           // Configuration of the Low Power Feature
    {
        .rssi_factor           = 0,                                 // contribution of the RSSI measured by the Friend node used in Friend Offer Delay 
                                                                        calculations.
        .receive_window_factor = 0,                                 // contribution of the supported Receive Window used in Friend Offer Delay calculations.
        .min_cache_size_log    = 0,                                 // minimum number of messages that the Friend node can store in its Friend Cache.
        .receive_delay         = 0,                                 // Receive delay in 1 ms units to be requested by the Low Power Node.
        .poll_timeout          = 0                                  // Poll timeout in 100ms units to be requested by the Low Power Node.
    },
    .gatt_client_only          = WICED_FALSE,                       // Can connect to mesh over GATT or ADV
    .elements_num  = (uint8_t)(sizeof(mesh_elements) / sizeof(mesh_elements[0])),   // number of elements on this device
    .elements      = mesh_elements                                  // Array of elements for this device
};

This section describes the five key steps required to implement this code example. These steps are already implemented in the provided code example and are described here for learning purposes.

Step 1: In this step, the Mesh Core configuration structure, wiced_bt_mesh_config_t, parameters are configured. The Dimmable Light Bulb Core Configuration Structure used for this example code is shown in Code 12.

Each parameter in this structure is explained in Mesh Device Configuration. Key items configured in this structure for the BLE_Mesh_LightDimmable code example are as follows:

.features = WICED_BT_MESH_CORE_FEATURE_BIT_FRIEND | WICED_BT_MESH_CORE_FEATURE_BIT_RELAY | WICED_BT_MESH_CORE_FEATURE_BIT_GATT_PROXY_SERVER

Step 2: In this step, parameters for the Mesh Core Element configuration structure, wiced_bt_mesh_core_config_element_t, are configured. The Dimmable Light Bulb Mesh Core Element Configuration code is shown in Code 13. This example contains one element.

Code 13. Dimmable Light Mesh Core Element Configuration Structure and Mesh Core Element Property Structure

wiced_bt_mesh_core_config_element_t mesh_elements[] =
{
    {
        .location = MESH_ELEM_LOC_MAIN,                                 // location description as defined in the GATT Bluetooth Namespace Descriptors section of 
                                                                           the Bluetooth SIG Assigned Numbers
        .default_transition_time = MESH_DEFAULT_TRANSITION_TIME_IN_MS,  // Default transition time for models of the element in milliseconds
        .onpowerup_state = WICED_BT_MESH_ON_POWER_UP_STATE_RESTORE,     // Default element behavior on power up
        .default_level = 0,                                             // Default value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .range_min = 1,                                                 // Minimum value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .range_max = 0xffff,                                            // Maximum value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .move_rollover = 0,                                             // If true when level gets to range_max during move operation, it switches to min, 
                                                                           otherwise move stops.
        .properties_num = MESH_APP_NUM_PROPERTIES,                      // Number of properties in the array models
        .properties = mesh_element1_properties,                         // Array of properties in the element.
        .sensors_num = 0,                                               // Number of sensors in the sensor array
        .sensors = NULL,                                                // Array of sensors of that element
        .models_num = MESH_APP_NUM_MODELS,                              // Number of models in the array models
        .models = mesh_element1_models,                                 // Array of models located in that element. Model data is defined by structure 
                                                                           wiced_bt_mesh_core_config_model_t
    },
}; 


wiced_bt_mesh_core_config_property_t mesh_element1_properties[] =
{
    {
        .id          = WICED_BT_MESH_PROPERTY_DEVICE_FIRMWARE_REVISION,
        .type        = WICED_BT_MESH_PROPERTY_TYPE_USER,
        .user_access = WICED_BT_MESH_PROPERTY_ID_READABLE,
        .max_len     = WICED_BT_MESH_PROPERTY_LEN_DEVICE_FIRMWARE_REVISION,
        .value       = mesh_prop_fw_version
    },
};
wiced_bt_mesh_core_config_model_t   mesh_element1_models[] =
{
    WICED_BT_MESH_DEVICE,
    WICED_BT_MESH_MODEL_USER_PROPERTY_SERVER,
    WICED_BT_MESH_MODEL_LIGHT_LIGHTNESS_SERVER,
};

Each parameter in this structure is explained in Mesh Element Configuration. Key parameters configured in this structure for the LightDimmable code example are as follows:

uint8_t mesh_prop_fw_version [WICED_BT_MESH_PROPERTY_LEN_DEVICE_FIRMWARE_REVISION] = {'0', '6', '.', '0', '2', '.', '0', '5' };

Code 14. Dimmable Light Application Function Definitions

wiced_bt_mesh_app_func_table_t wiced_bt_mesh_app_func_table =
{
    mesh_app_init,          // application initialization
    NULL,                   // Default SDK platform button processing
    NULL,                   // GATT connection status
    mesh_app_attention,     // attention processing
    NULL,                   // notify period set
    NULL,                   // WICED HCI command
    NULL,                   // LPN sleep
    NULL                    // factory reset
};

Step 3: This step registers the application callback functions used for the code example. The Mesh application initialization and Mesh application attention callback functions are defined in the wiced_bt_mesh_app_func_table_t structure. The Mesh Core Library performs default actions as defined in the mesh_application.c file for the items which do not have any callback function registered in this structure.

Code 15. mesh_app_init() Function

void mesh_app_init(wiced_bool_t is_provisioned)
{
#if 0
    extern uint8_t wiced_bt_mesh_model_trace_enabled;
    wiced_bt_mesh_model_trace_enabled = WICED_TRUE;
#endif
    wiced_bt_cfg_settings.device_name = (uint8_t *)"Dimmable Light";
    wiced_bt_cfg_settings.gatt_cfg.appearance = APPEARANCE_LIGHT_CEILING;

    mesh_prop_fw_version[0] = 0x30 + (WICED_SDK_MAJOR_VER / 10);
    mesh_prop_fw_version[1] = 0x30 + (WICED_SDK_MAJOR_VER % 10);
    mesh_prop_fw_version[2] = 0x30 + (WICED_SDK_MINOR_VER / 10);
    mesh_prop_fw_version[3] = 0x30 + (WICED_SDK_MINOR_VER % 10);
    mesh_prop_fw_version[4] = 0x30 + (WICED_SDK_REV_NUMBER / 10);
    mesh_prop_fw_version[5] = 0x30 + (WICED_SDK_REV_NUMBER % 10);
    mesh_prop_fw_version[6] = 0x30 + (WICED_SDK_BUILD_NUMBER / 10);
    mesh_prop_fw_version[7] = 0x30 + (WICED_SDK_BUILD_NUMBER % 10);

    // Adv Data is fixed. Spec allows to put URI, Name, Appearance and Tx Power in the Scan Response Data.
    if (!is_provisioned)
    {
        wiced_bt_ble_advert_elem_t  adv_elem[3];
        uint8_t                     buf[2];
        uint8_t                     num_elem = 0;

        adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_NAME_COMPLETE;
        adv_elem[num_elem].len         = (uint16_t)strlen((const char*)wiced_bt_cfg_settings.device_name);
        adv_elem[num_elem].p_data      = wiced_bt_cfg_settings.device_name;
        num_elem++;

        adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_APPEARANCE;
        adv_elem[num_elem].len         = 2;
        buf[0]                         = (uint8_t)wiced_bt_cfg_settings.gatt_cfg.appearance;
        buf[1]                         = (uint8_t)(wiced_bt_cfg_settings.gatt_cfg.appearance >> 8);
        adv_elem[num_elem].p_data      = buf;
        num_elem++;

        wiced_bt_mesh_set_raw_scan_response_data(num_elem, adv_elem);
    }

    led_control_init();

    wiced_init_timer(&attention_timer, attention_timer_cb, 0, WICED_SECONDS_PERIODIC_TIMER);

    // Initialize Light Lightness Server and register a callback which will be executed when it is time to change the brightness of the bulb
    wiced_bt_mesh_model_light_lightness_server_init(MESH_LIGHT_LIGHTNESS_SERVER_ELEMENT_INDEX, mesh_app_message_handler, is_provisioned);

    // Initialize the Property Server.  We do not need to be notified when Property is set, because our only property is readonly
    wiced_bt_mesh_model_property_server_init(MESH_LIGHT_LIGHTNESS_SERVER_ELEMENT_INDEX, NULL, is_provisioned);
}

Step 4: This step implements the application callback functions. There are two application callback functions defined for the BLE_Mesh_LightDimmable code example, mesh_app_init() and mesh_app_attention(). Each is described below.

1.mesh_app_init()

In this function shown in Code 15, the following actions are performed:

Code 16. mesh_app_attention() Function

void mesh_app_attention(uint8_t element_idx, uint8_t time)
{
    WICED_BT_TRACE("dimmable light attention:%d sec\n", time);

    // If time is zero, stop alerting and restore the last known brightness
    if (time == 0)
    {
        wiced_stop_timer(&attention_timer);
        led_control_set_brighness_level(last_known_brightness);
        return;
    }
    wiced_start_timer(&attention_timer, 1);
    attention_time = time;
    attention_brightness = (last_known_brightness != 0) ? 0 : 100;
    led_control_set_brighness_level(attention_brightness);
}
/*
 * Attention timer callback is executed every second while user needs to be alerted.
 * Just switch brightness between 0 and 100%
 */
void attention_timer_cb(TIMER_PARAM_TYPE arg)
{
    WICED_BT_TRACE("dimmable light attention timeout:%d\n", attention_time);

    if (--attention_time == 0)
    {
        wiced_stop_timer(&attention_timer);
        led_control_set_brighness_level(last_known_brightness);
        return;
    }
    attention_brightness = (attention_brightness == 0) ? 100 : 0;
    led_control_set_brighness_level(attention_brightness);
}

2.mesh_app_attention()

The callback function, mesh_app_attention, shown in Code 16 is triggered by the Mesh Core Library for the developer to implement logic that can alert the user (e.g., provide the user with a visual indication of which device is being provisioned). A periodic seconds timer called attention timer is started in this function. In this example, the LED state is toggled (ON/OFF) every second in the callback function `attention_timer_cb until the attention timer expires.

Code 17. mesh_app_message_handler(), mesh_app_process_set(), and led_control_set_brightness_level() Functions

void mesh_app_message_handler(uint8_t element_idx, uint16_t event, void *p_data)
{
    switch (event)
    {
    case WICED_BT_MESH_LIGHT_LIGHTNESS_SET:
        mesh_app_process_set_level(element_idx, (wiced_bt_mesh_light_lightness_status_t *)p_data);
        break;

    default:
        WICED_BT_TRACE("dimmable light unknown msg:%d\n", event);
        break;
    }
}
/*
 * Command from the level client is received to set the new level
 */
void mesh_app_process_set_level(uint8_t element_idx, wiced_bt_mesh_light_lightness_status_t *p_status)
{
    WICED_BT_TRACE("mesh light srv set level element:%d present actual:%d linear:%d remaining_time:%d\n",
        element_idx, p_status->lightness_actual_present, p_status->lightness_linear_present, p_status->remaining_time);

    last_known_brightness = (uint8_t)((uint32_t)p_status->lightness_actual_present * 100 / 65535);
    led_control_set_brighness_level(last_known_brightness);

    // If we were alerting user, stop it.
    wiced_stop_timer(&attention_timer);
}

void led_control_set_brighness_level(uint8_t brightness_level)

{
    pwm_config_t pwm_config;

    WICED_BT_TRACE("set brightness:%d\n", brightness_level);

    // ToDo.  For some reason, setting brightness to 100% does not work well on 20719B1 platform. For now just use 99% instead of 100.
    if (brightness_level == 100)
        brightness_level = 99;

    wiced_hal_pwm_get_params(PWM_INP_CLK_IN_HZ, brightness_level, PWM_FREQ_IN_HZ, &pwm_config);
    wiced_hal_pwm_change_values(PWM_CHANNEL, pwm_config.toggle_count, pwm_config.init_count);
}

Step 5: This step implements the Mesh message callback functions.

When a message is received, the Dimmable Light Bulb node gets a callback to the function registered during initialization, mesh_app_message_handler. This callback function, shown in Code 17, is triggered by the Mesh Models Library on receipt of relevant Mesh messages for the BLE Mesh Light Lightness Server model. If the callback function receives the WICED_BT_MESH_LIGHT_LIGHTNESS_SET event, the mesh_app_process_set function (shown in Code 17) is called, which interprets the received data and performs the appropriate action. The Light Lightness Actual State (p_status to lightness_actual_present) is sent as the parameter to the callback function, which defines the level (brightness) value for the Dimmable Light node. As the Light Lightness Actual state can have values between 0 to 65535, we scale this value from 0 to 100% and pass it as the parameter to the led_control_set_brightness() function which is also shown in Code 17. In this function, the PWM values are modified according to the received level setting to control the intensity of the LED.

Use Case #2: Low-Power ON/OFF Server with Three Dimmable Light Bulbs

Figure 28. Low Power ON/OFF Server and Three Dimmable Light Bulbs

There are two code examples associated with Use Case #2. These code examples are described in Sections Low-Power ON/OFF Server and Dimmable Light Bulb.

In this use case, one of the Mesh evaluation boards is programmed as a Low-Power ON/OFF Server and the other three are programmed as Dimmable Light Bulbs. The Low-Power ON/OFF Server represents any LPN whose primary function is to receive information from the Mesh network and act on it locally.

An example of the Low-Power ON/OFF Server would be a Door Lock, where the device is not required to be active all the time, but only at specific intervals. In this use case example, the Low-Power ON/OFF Server uses the Red LED on the Mesh evaluation board to represent an ON or OFF status (the Red LED ON represents the door being unlocked, and the Red LED OFF represents the door being locked). The Dimmable Light Bulbs use the Red LED of the Mesh evaluation board to represent a light bulb. The Low-Power ON/OFF Server code example uses WICED_BT_MESH_MODEL_POWER_ONOFF_SERVER model which allows the Provisioner to configure the power up state behavior. For example, you may always want the door to be locked (OFF) at power up while for another application, you may want the power up state to be ON. The model WICED_BT_MESH_MODEL_POWER_ONOFF_SERVER allows you to configure the power up state based on the application's requirement.

This use case demonstrates the LPN, Server, Relay, Friend, and Proxy features of Bluetooth Mesh.

The poll time interval (the time at which the LPN will wake and query its Friend) for the Low-Power ON/OFF Server node is defined in its application code locally. There is no interval configuration from the Helper application because the Low-Power ON/OFF Server LPN is not sending information into the network, it is only receiving.

Figure 28 details the setup for Use Case #2. In the illustration, Dimmable Light Bulb #1 is assumed to be the selected Friend node for the Low-Power ON/OFF Server node. In your setup, the Friend will be automatically selected based on the Friendship establishment process as documented in Section Friend Node and LPN Configuration

Low-Power ON/OFF Server Code Example

Low-Power ON/OFF Server Characteristics

low_power_led Code Example

Figure 29. Low-Power ON/OFF Server ModusToolbox Application Settings Configuration for LPN

This code example is provided on GitHub. This section describes the five key steps required to implement this code example. These steps are already implemented in the code example provided and are described here for learning purposes.

Step 1:

Code 18. Low-Power LED Bluetooth Mesh Core Configuration Structure

wiced_bt_mesh_core_config_t  mesh_config =
{
    .company_id         = MESH_COMPANY_ID_CYPRESS,                  // Company identifier assigned by the Bluetooth SIG
    .product_id         = MESH_PID,                                 // Vendor-assigned product identifier
    .vendor_id          = MESH_VID,                                 // Vendor-assigned product version identifier
    .firmware_id        = MESH_FWID,                                // Vendor-assigned firmware version identifier
    .replay_cache_size  = MESH_CACHE_REPLAY_SIZE,                   // Number of replay protection entries, i.e. maximum number of mesh devices that can send 
                                                                       application messages to this device.
#if defined(LOW_POWER_NODE) && (LOW_POWER_NODE == 1)
    .features           = WICED_BT_MESH_CORE_FEATURE_BIT_LOW_POWER, // A bit field indicating the device features. In Low Power mode no Relay, no Proxy and no 
                                                                       Friend
    .friend_cfg         =                                           // Empty Configuration of the Friend Feature
    {
        .receive_window = 0,                                        // Receive Window value in milliseconds supported by the Friend node.
        .cache_buf_len  = 0,                                        // Length of the buffer for the cache
        .max_lpn_num    = 0                                         // Max number of Low Power Nodes with established friendship. Must be > 0 if Friend feature is 
                                                                       supported. 
    },
    .low_power          =                                           // Configuration of the Low Power Feature
    {
        .rssi_factor           = 2,                                 // contribution of the RSSI measured by the Friend node used in Friend Offer Delay 
                                                                       calculations.
        .receive_window_factor = 2,                                 // contribution of the supported Receive Window used in Friend Offer Delay calculations.
        .min_cache_size_log    = 3,                                 // minimum number of messages that the Friend node can store in its Friend Cache.
        .receive_delay         = 100,                               // Receive delay in 1 ms units to be requested by the Low Power Node.
        .poll_timeout          = 200                                // Poll timeout in 100ms units to be requested by the Low Power Node.
    },
#else
    .features = WICED_BT_MESH_CORE_FEATURE_BIT_FRIEND | WICED_BT_MESH_CORE_FEATURE_BIT_RELAY | WICED_BT_MESH_CORE_FEATURE_BIT_GATT_PROXY_SERVER,   // Supports 
                                                                       Friend, Relay and GATT Proxy
    .friend_cfg         =                                           // Configuration of the Friend Feature(Receive Window in Ms, messages cache)
    {
        .receive_window        = 200,
        .cache_buf_len         = 300,                               // Length of the buffer for the cache
        .max_lpn_num           = 4                                  // Max number of Low Power Nodes with established friendship. Must be > 0 if Friend feature is  
                                                                       supported. 
    },
    .low_power          =                                           // Configuration of the Low Power Feature
    {
        .rssi_factor           = 0,                                 // contribution of the RSSI measured by the Friend node used in Friend Offer Delay 
                                                                       calculations.
        .receive_window_factor = 0,                                 // contribution of the supported Receive Window used in Friend Offer Delay calculations.
        .min_cache_size_log    = 0,                                 // minimum number of messages that the Friend node can store in its Friend Cache.
        .receive_delay         = 0,                                 // Receive delay in 1 ms units to be requested by the Low Power Node.
        .poll_timeout          = 0                                  // Poll timeout in 100ms units to be requested by the Low Power Node.
    },
#endif
    .gatt_client_only          = WICED_FALSE,                       // Can connect to mesh over GATT or ADV
    .elements_num  = (uint8_t)(sizeof(mesh_elements) / sizeof(mesh_elements[0])),   // number of elements on this device
    .elements      = mesh_elements                                  // Array of elements for this device
};

In this step, parameters of the Mesh Core configuration structure, wiced_bt_mesh_config_t, are configured. The Low-Power ON/OFF Server Mesh Core Configuration code is shown in Code 18.

Each parameter in this structure is explained in Mesh Device Configuration. The key items configured in this structure for the Low-Power ON/OFF Server (low_power_led) code example are as follows:

Based on the status of the LOW_POWER_NODE macro, the Low-Power ON/OFF Server device can act as a Power OnOff Server with the LPN feature (target implementation) OR as a Power OnOff Server which supports Friend, Relay, and GATT Proxy features (if the LOW_POWER_NODE macro is not enabled).

Step 2:

Code 19. Low-Power LED Bluetooth Mesh Core Configuration Element Structure

wiced_bt_mesh_core_config_element_t mesh_elements[] =
{
    {
        .location = MESH_ELEM_LOC_MAIN,                                 // location description as defined in the GATT Bluetooth Namespace Descriptors section of 
                                                                           the Bluetooth SIG Assigned Numbers
        .default_transition_time = MESH_DEFAULT_TRANSITION_TIME_IN_MS,  // Default transition time for models of the element in milliseconds
        .onpowerup_state = WICED_BT_MESH_ON_POWER_UP_STATE_RESTORE,     // Default element behavior on power up
        .default_level = 0,                                             // Default value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .range_min = 1,                                                 // Minimum value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .range_max = 0xffff,                                            // Maximum value of the variable controlled on this element (for example power, lightness, 
                                                                           temperature, hue...)
        .move_rollover = 0,                                             // If true when level gets to range_max during move operation, it switches to min, 
                                                                           otherwise move stops.
        .properties_num = 0,                                            // Number of properties in the array models
        .properties = mesh_element1_properties,                         // Array of properties in the element.
        .sensors_num = 0,                                               // Number of sensors in the sensor array
        .sensors = NULL,                                                // Array of sensors of that element
        .models_num = (sizeof(mesh_element1_models) / sizeof(wiced_bt_mesh_core_config_model_t)),    // Number of models in the array models
        .models = mesh_element1_models,                                 // Array of models located in that element. Model data is defined by structure 
                                                                           wiced_bt_mesh_core_config_model_t
    },
};
wiced_bt_mesh_core_config_model_t   mesh_element1_models[] =
{
    WICED_BT_MESH_DEVICE,
    WICED_BT_MESH_MODEL_POWER_ONOFF_SERVER,
};

In this step, parameters of the Mesh Core Element configuration structure, wiced_bt_mesh_core_config_element_t, are configured. The Low-Power ON/OFF Server Mesh Core Elements Configuration code is shown in Code 19. This example has one element.

Each parameter in this structure is explained in Mesh Element Configuration. Key items configured in this structure for the low_power_led (Low-Power ON/OFF Server) code example are as follows:

Step 3:

Code 20. Low-Power LED Bluetooth Mesh Application Function Table

wiced_bt_mesh_app_func_table_t wiced_bt_mesh_app_func_table =
{
    mesh_app_init,          // application initialization
    NULL,                   // Default SDK platform button processing
    NULL,                   // GATT connection status
    NULL,                   // attention processing
    NULL,                   // notify period set
    NULL,                   // WICED HCI command
#if defined(LOW_POWER_NODE) && (LOW_POWER_NODE == 1)
    mesh_low_power_led_lpn_sleep,// LPN sleep
#else
    NULL,
#endif
    NULL                    // factory reset
};

This step registers application functions for the code example.

In this project, the Mesh application initialization and Mesh LPN Sleep callback functions are defined in the wiced_bt_mesh_app_func_table_tstructure as shown in Code 20. The Mesh Core Library performs default actions as defined in mesh_application.c for the items that do not have any callback function registered in this structure.

Step 4:

Code 21. Low-Power LED mesh_app_init Mesh Application Initialization Function

void mesh_app_init(wiced_bool_t is_provisioned)
{
#if 0
    extern uint8_t wiced_bt_mesh_model_trace_enabled;
    wiced_bt_mesh_model_trace_enabled = WICED_TRUE;
#endif
    wiced_result_t  result;

#if defined(LOW_POWER_NODE) && (LOW_POWER_NODE == 1)
    wiced_bt_cfg_settings.device_name = (uint8_t *)"Low Power Led";
#else
    wiced_bt_cfg_settings.device_name = (uint8_t *)"Lighting Element";
#endif
    wiced_bt_cfg_settings.gatt_cfg.appearance = APPEARANCE_GENERIC_TAG;

    // Adv Data is fixed. Spec allows to put URI, Name, Appearance and Tx Power in the Scan Response Data.
    if (!is_provisioned)
    {
        wiced_bt_ble_advert_elem_t  adv_elem[3];
        uint8_t                     buf[2];
        uint8_t                     num_elem = 0;

        adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_NAME_COMPLETE;
        adv_elem[num_elem].len         = (uint16_t)strlen((const char*)wiced_bt_cfg_settings.device_name);
        adv_elem[num_elem].p_data      = wiced_bt_cfg_settings.device_name;
        num_elem++;

        adv_elem[num_elem].advert_type = BTM_BLE_ADVERT_TYPE_APPEARANCE;
        adv_elem[num_elem].len         = 2;
        buf[0]                         = (uint8_t)wiced_bt_cfg_settings.gatt_cfg.appearance;
        buf[1]                         = (uint8_t)(wiced_bt_cfg_settings.gatt_cfg.appearance >> 8);
        adv_elem[num_elem].p_data      = buf;
        num_elem++;

        wiced_bt_mesh_set_raw_scan_response_data(num_elem, adv_elem);
    }

    mesh_prop_fw_version[0] = 0x30 + (WICED_SDK_MAJOR_VER / 10);
    mesh_prop_fw_version[1] = 0x30 + (WICED_SDK_MAJOR_VER % 10);
    mesh_prop_fw_version[2] = 0x30 + (WICED_SDK_MINOR_VER / 10);
    mesh_prop_fw_version[3] = 0x30 + (WICED_SDK_MINOR_VER % 10);
    mesh_prop_fw_version[4] = 0x30 + (WICED_SDK_REV_NUMBER / 10);
    mesh_prop_fw_version[5] = 0x30 + (WICED_SDK_REV_NUMBER % 10);
    mesh_prop_fw_version[6] = 0x30 + (WICED_SDK_BUILD_NUMBER / 10);
    mesh_prop_fw_version[7] = 0x30 + (WICED_SDK_BUILD_NUMBER % 10);

    wiced_bt_mesh_model_power_onoff_server_init(MESH_LOW_POWER_LED_ELEMENT_INDEX, mesh_low_power_led_message_handler, is_provisioned);
}

This step implements the application callback functions.
There are two application callback functions defined for the low_power_led code example, mesh_app_init() and mesh_low_power_led_lpn_sleep(). Each is described below.

1.mesh_app_init()

This function shown in Code 21 performs the following actions:

2.mesh_low_power_led_lpn_sleep()

Code 22. Low-Power LED Sleep/HID-Off Function

#if defined(LOW_POWER_NODE) && (LOW_POWER_NODE == 1)
void mesh_low_power_led_lpn_sleep(uint32_t max_sleep_duration)
{
    if(WICED_SUCCESS != wiced_sleep_enter_hid_off( max_sleep_duration, WICED_GPIO_PIN_BUTTON, 1))
    {
        WICED_BT_TRACE("Entering HID-Off failed\n\r");
    }
}
#endif

The Mesh Core Library triggers this function for the Low-Power ON/OFF Server application project to decide whether it wants to enter a low-power state. The Low-Power ON/OFF Server project can go to a sleep state for a duration not to exceed the max_sleep_duration (time in milliseconds), which is passed as a parameter to this function. In this case, the HID-OFF sleep mode is initiated with max_sleep_duration and User Button SW3 GPIO (WICED_GPIO_PIN_BUTTON) set as a wakeup source as shown in Code 22. These parameters are used for wiced_sleep_enter_hid_off.

Step 5:

Code 23. Low-Power LED Mesh Message Callback Functions

void mesh_low_power_led_message_handler(uint8_t element_idx, uint16_t event, void *p_data)
{
    switch (event)
    {
    case WICED_BT_MESH_ONOFF_SET:
        mesh_low_power_led_process_set(element_idx, (wiced_bt_mesh_onoff_status_data_t *)p_data);
        break;

    default:
        WICED_BT_TRACE("unknown\n");
    }
}
/*
 * This function is called when command to change state is received over mesh.
 */
void mesh_low_power_led_process_set(uint8_t element_idx, wiced_bt_mesh_onoff_status_data_t *p_status)
{
    uint8_t written_byte = 0;
    wiced_result_t status;

    WICED_BT_TRACE("onoff srv set onoff: present:%d target:%d remaining:%d\n", p_status->present_onoff, p_status->target_onoff, p_status->remaining_time);
    led_control_set_onoff(p_status->present_onoff);
}

void led_control_set_onoff(uint8_t onoff_value)
{
    if(onoff_value >= 1)//led is on
    {
        wiced_hal_gpio_configure_pin(led_pin, GPIO_OUTPUT_ENABLE, GPIO_PIN_OUTPUT_LOW);
    }
    else if(onoff_value == 0)//led is off
    {
        wiced_hal_gpio_configure_pin(led_pin, GPIO_OUTPUT_ENABLE, GPIO_PIN_OUTPUT_HIGH);
    }
}

This step implements the Mesh message callback functions.

The Low Power ON/OFF Server node receives Mesh messages in the callback function, mesh_app_message_handler, registered during initialization. Details of the Mesh message for this model are received as parameters to this callback function. The mesh_app_message_handler is triggered by the Mesh Models Library on receipt of Mesh messages intended for the BLE Mesh Power OnOff Server model. If this callback function receives the WICED_BT_MESH_ONOFF_SET event, the mesh_low_power_led_process_set function is called, which interprets the received message and calls the led_control_set_onoff function with the desired LED state as the parameter. The led_control_set_onoff function controls the LED state based on the received Mesh messages.

Dimmable Light Code Example

The Dimmable Light used in this use case is the same as the one used in Use Case#1. See Dimmable Light Bulb Code Example. However, the Friend feature that is enabled in the code example is not utilized in Use Case #1 but it is used in Use Case #2. The Friend feature of the Dimmable Light Bulbs allows the Low-Power ON/OFF Server node to establish friendship with one of the Dimmable Light Bulbs in the network so that it can receive messages that are intended for the Low-Power ON/OFF Server node.

Programming the Evaluation Boards

This section details the steps required to program the CYBT-213043-MESH EZ-BT Bluetooth Mesh Evaluation Board. The CYBT-213043-02 module on the CYBT-213043-MESH Mesh evaluation boards include a UART-based bootloader in the on-chip ROM, and therefore does not require an external programmer. Boards are programmed over the UART interface using the on-board Cypress USB-UART device. For more details on the programming hardware included on the Mesh Evaluation boards, see sections Active Devices and Connectors and Headers. The code examples discussed in this application note are available in two locations: ModusToolbox and GitHub. This section covers how to build and program code examples from both sources.

Programing Code Examples Provided with the BT SDK

Figure 30. Creating a New ModusToolbox IDE Application

Figure 31. Selecting Target Hardware

Figure 32. Selecting Starter Application and Assigning a Name to The Application

Figure 33. Summary of Application Creation

Figure 34. Readme Files to Learn About the Kit and the Application Code Example

Figure 35. Setting BLE_Mesh_LightDimmable as Active Project

If you are programming code examples that are provided in the BT-SDK, continue with the following steps.

  1. Launch ModusToolbox from your machine’s Start Menu or desktop shortcut if you created one at the time of installation.
  2. Go to File > New > ModusToolbox IDE Application.
  3. Select the Target Hardware that you want to use for your application. We are using the CYBT-213043-MESH in this example. Select CYBT-213043-MESH, and then click Next.
  4. Select the code example that you want to program to the board. For example, select BLE_Mesh_LightDimmable. Once selected, the Application Name will be populated with the default name. You can leave it unchanged or change it to a name you wish to use. Then click Next.
  5. Figure 33 provides the summary of the Device and Board selected for your application. It also provides the code example name. Click Finish to create the application.
  6. Once the application is created, it will open two readme files – readme.txt and 20819_readme.txt. Explore both files to learn about code example details and CYW20819 features offered by the BT SDK.
  7. Click on BLE_Mesh_LightDimmable under the Project Explorer. BLE_Mesh_LightDimmable will then be set as the active project. This step may not be required if this is the only project in the workspace. Once done, several launchers will be available in Quick Panel.
  8. Click on BLE_Mesh_LightDimmable Build + Program in Quick Panel under Launches to initiate the build and programming process. Once programming is complete, it will display a “Download Succeeded” message in the console. The output after successful programming of the board is shown in Figure 36.

Figure 36. Programming the Board

Programing GitHub Examples

Figure 37. Creating a New ModusToolbox IDE Application

Figure 38. Selecting the Target Hardware

Figure 39. Importing a Project Downloaded from GitHub

Figure 40. Browsing to the Starter Project in the Unzipped Folder Downloaded from GitHub

Figure 41. Selecting Imported Project as the Starter Application

Figure 42. Project Creation Summary

Figure 43. Programming the Board

If you are programming code examples that are provided on GitHub, continue with the following steps.

  1. The first step is to download the code example from GitHub. You can follow the link in this document or you can click on “Search Online for Code Examples” in the quick panel in ModusToolbox IDE and then click the link for 20819A1 Bluetooth Examples.
  2. Click on Clone or download button on the GitHub repository. Then click on Download ZIP. A ZIP file will be downloaded with the name Code-Examples-BT-20819A1-x.x-for-ModusToolbox-modustoolboxx.x.x.zip. This ZIP file will contain all code examples for the specific ModusToolbox BT SDK version selected.
  3. Unzip the file.
  4. Launch ModusToolbox from your machine’s Start Menu or Desktop shortcut.
  5. Go to File > New > ModusToolbox IDE Application.
  6. Select the Target Hardware that you want to use for your application. We are using CYBT-213043-MESH in this example. Select CYBT-213043-MESH and then click Next.
  7. Click on Import. A Windows Explorer window will appear to select the code example that you wish to use.
  8. Navigate to the unzipped folder downloaded from GitHub and select the code example that you want to program. GitHub provides information and details for each code example that was downloaded in Step 2 above. Once you have selected the code example you want to use, click Open. As part of these instructions, we have used the Dimmer code example that is located at CYBT-213043-MESH/apps/demo/mesh/dimmer/modus.mk.
  9. A new BLE_Mesh_Dimmer* project will appear in the selection window. Note that any project that is not already included in the BT SDK will have a “*” suffix. Select this project and click Next. Also notice that the window provides the path to the source that this project is created from.
  10. Click Finish to create the project.
  11. To program the board, click on BLE_Mesh_Dimmer_mainapp under Project Explorer. It will set BLE_Mesh_LightDimmable as the active project. This step may not be required if this is the only project in the workspace. Once done, several launchers will be available in Quick Panel. Click on BLE_Mesh_Dimmer Build + Program in the Quick Panel under Launches. It will initiate the build and programming process. Once programming is complete, it will show the “Download Succeeded” message in the console output. The output after successful programming of the board is shown in Figure 43.

Performing a Recovery Procedure

In some cases, the normal firmware download procedure does not succeed even though all connections and switches are correct. This may happen as a result of flash corruption or power loss during a normal firmware download process. It may also happen if the device is in a low-power mode. If this happens, you may need to recover the device (i.e., force it into a mode where it is listening for programming instructions). Do the following to put the device in to recovery mode.

  1. Ensure that the HCI UART is connected to the module (via direct connection) or evaluation board (via configuration switches). This step is required only if you want to reprogram your module after the following recovery procedure has completed.
  2. Press and hold the RECOVER button SW2 (Red button).
  3. Press and release the RESET button SW1 (Blue button).
  4. Release the RECOVER button (Red button).
  5. Re-program the board using the launcher in ModusToolbox.

Testing the Code Examples

This section describes how to test the two use cases outlined in this application note.

To test these use cases, make sure that you have all hardware and software as described in Prerequisites.

Testing Use Case #1

Figure 44. Use Case #1 Setup: Dimmer Switch with Three Dimmable Light Bulbs

Follow the steps below to download and demonstrate the Mesh functionality described in Use Case #1.

1.Program the CYBT-213043-MESH boards with following projects. Refer to programming instructions in Programming the Evaluation Boards to program the Mesh evaluation boards.

2.Make sure that your iOS device has the MeshLightingController application installed. For steps to install the MeshLightingController application on your iOS device, see iOS Helper App Installation.

3.Open the MeshLightingController app on your iOS device.

Figure 45. Creating a Mesh Network

4.Do the following to create a Mesh network:

a. Tap +ADD NETWORK located towards the top right of the MeshLightingController application.

b. A new window pops up where a network can be created. In this case, the network name is assigned as “cypress”; you can use your own network name here as desired.

c. Tap Confirm.

d. Observe that a new network with the name “cypress” is created with a default group called “All”

Figure 46. Creating a Group in the Mesh Network

Figure 47. Scan for Unprovisioned Mesh Devices

Figure 48. Provision a Dimmable Light Bulb Node

Figure 49. Provision Dimmer Switch Node

5.Next, tap on the cypress network on the MeshLightingController app home. A new screen will appear as shown below in Figure 46. Tap the +Add A GROUP” button located towards the top right side of the MeshLightingController application. Enter your desired name for this group and tap Confirm. In this example below, the name of the group is “Building 6.2”.

6.After creating the Mesh Network and Group, you can add the Mesh devices to the network/group. Tap on Building 6.2 group and then tap on the +ADD DEVICE button to see the unprovisioned Mesh devices in the vicinity as shown in Figure 47. You will see the advertisement of the four Mesh Evaluation boards that we programmed in Step 1 of this section.

7.Tap on the Dimmable Light device to start the “Provisioning” and “Configuration” process. Observe the status message “Provision Success” after the process is complete. Now, the Dimmable Light Bulb with the name Dimmable Light (002) is part of the Mesh Group. The “(002)” shown in this example is an auto-generated post-fix representing the element unique address for the node.

8.Repeat Step 6 and 7 to add the other two Dimmable Light Bulbs and the Dimmer Switch.

Figure 50. All Provisioned Nodes in The Group

9.At this point, all four nodes are part of the Mesh Group (in this case, the name of the group is “Building 6.2”) as shown below. The Dimmer Switch is automatically configured to control the Dimmable Light Bulbs as both Dimmer and LightDimmable devices are part of the same group.

Figure 51. Controlling Dimmable Light Bulb

Figure 52. Controlling All Three Dimmable Light Bulbs in Group “Building 6.2”

10.The LED on the Dimmable Light Mesh nodes can be controlled in the following ways:

a. Tap on the ON/OFF button corresponding to the Dimmable Light on the MeshLightController app and observe that each Dimmable Light Bulb can be controlled independently. Tap on any Dimmable Light device, in this case Dimmable Light (0002). The level setting of the LED on Dimmable Light Bulb can be controlled by varying the linear slider between 0 to 100%.

b. For group control, tap twice on the blue back arrow located towards the top left side of the MeshLightingController app screen and select “Group Controls” to control a group’s ON/OFF status or level.

c. The Dimmer Switch node can also control the Dimmable Light Bulbs directly without the need of the Cypress iOS Helper app. The Dimmer Switch controls the LED on the three Dimmable Light Bulbs through the User Button on the Dimmer Switch evaluation board. The User Button actions and associated Mesh messages that are sent out from the Dimmer Switch are detailed below:

Testing Use Case #2

Figure 53. Testing Use Case #2: Low-Power ON/OFF Server with Three Dimmable Light Bulbs

Figure 54. Creating a Mesh Network

Figure 55. Creating a Group in the Mesh Network

Figure 56. Scanning Unprovisioned Mesh Devices

Figure 57. Adding Dimmable Light Bulb to the Group

Figure 58. Adding Low-Power ON/OFF Server to the Group

Figure 59. One Low-Power ON/OFF Server and Three Dimmable Light Bulbs in the Group

Figure 60. Controlling One Dimmable Light Bulb

Follow the steps below to download and demonstrate the Mesh functionality described in Use Case #3.

1.Program the CYBT-213043-MESH boards with the following applications. Refer to instructions in Programming the Evaluation Boards to program the Mesh evaluation boards.

Figure 53 details the setup for Use Case #2. In the illustration, Dimmable Light Bulb #1 is assumed to be the selected Friend node for the Low-Power ON/OFF Server node. In your setup, the Friend will be automatically selected based on the Friendship establishment process as documented in Section Friend Node and LPN Configuration.

2.Make sure that your iOS device has the MeshLightingController app. Steps to install MeshLightingController app on your iOS device are detailed in Figure 68. Tap on the +Add A GROUP button located towards the top right side of the MeshLightingController app screen. Enter your desired name for this group and tap Confirm. In this example below, the name of the group is “Building 6.2”.

6.After creating the Mesh Network and Group, you can add the Mesh devices to the network/group. Tap on the Building 6.2 group and then tap on the +ADD DEVICE button to see the unprovisioned Mesh devices in the vicinity as shown in Figure 56. You will see the advertisement of the four Mesh Evaluation boards that programmed in Step 1 of this section.

7.Tap on the Dimmable Light device to start the “Provisioning” and “Configuration” process. Observe that status message “Provision Success” after the process is complete. Now the Dimmable Light Bulb with the name Dimmable Light (002) is part of the Mesh network. The “(002)” shown in this example is an auto-generated post-fix representing the element unique address for the node.

8.Repeat steps 6 and 7 to add other two Dimmable Light Bulbs and the Low-Power ON/OFF Server.

9.At this point, all four nodes are part of the Mesh Group (in this case the name of the group is “Building 6.2”) as shown below. The Low-power ON/OFF Server automatically creates friendship with one of the Dimmable Light Bulbs. The Mesh Core Library will take care of the Friendship establishment process.

10.The LED on the Dimmable Light Bulbs and the Low-Power ON/OFF Server can be controlled in the following ways:

a. Tap on the ON/OFF button corresponding to the Dimmable Light Bulb in the MeshLightController app screen and observe that the LED on the corresponding Dimmable Light Bulb boards can be controlled independently. Tap on any Dimmable Light, in this case Dimmable Light (0002), and observe a linear slider. The level setting of each Dimmable Light Bulb node can be controlled by varying the linear slider between 0 to 100%.

b. Tap on the ON button corresponding to Low-Power ON/OFF Server. Observe that there is a delay of up to 17 seconds for the LED to turn ON. This is due to the fact that the Low-Power ON/OFF Server will poll its Friend for any cached messages approximately every 17 seconds. The Low-Power ON/OFF Server will stay in the lowest possible power state during the period when it is not polling its Friend (Sleep period). The delay will not be constant since it depends when in the sleep cycle the message is sent. Likewise, click the OFF button and observe the delay in turning the LED OFF.

c. For group control, tap twice on the blue back arrow located towards the top left side of the MeshLightingController app screen. Tap the ON button under group controls; you will observe that Dimmable Light Bulbs’ LEDs turn ON instantly, but the LED on the Low-Power LED could take up to 17 seconds to turn ON. Tap on the lightness option to control the level of the LEDs on the Dimmable Light Bulbs. The LED on the Low-Power ON/OFF Server board uses a GPIO to control the LED; therefore, it cannot control the level setting whereas the LED on the Dimmable Light Bulbs are controlled by a PWM, providing the ability to control the level setting.

Figure 61. Sending a Set Message to All Nodes in Group “Building 6.2”

Summary

This application note introduces you to Cypress’ Bluetooth SIG-compliant Mesh solution. It provides an overview of Bluetooth Mesh and its key concepts as well as how to get started with Cypress’ BLE Mesh solution for your applications. This application note provides details on various software tools, including mobile applications, as well as the CYBT-213043-MESH evaluation kit offered by Cypress as part of its Bluetooth Mesh offering. Cypress offers many code examples to help evaluate and design Bluetooth Mesh applications. This application note covers Cypress’ BLE Mesh architecture, code structure, and how make changes based on your application needs.

Related Application Notes

Appendix

Appendix A. Understanding the Flow of the Cypress Mesh Application Library

This appendix section takes you through the Mesh Application library code flow that includes initializing a Mesh GATT database, registering GATT callbacks, registering Mesh-specific callback functions with the Mesh Core, initializing the firmware upgrade library, setting the output TX power level, and other Mesh-related items which do not need hardware-specific knowledge. All initialization and actions which are specific to hardware must be implemented in the Mesh user application code as shown in the code examples.

The main blocks of the Mesh Application library implementation in the BT SDK with ModusToolbox IDE are:

  1. System Bluetooth Parameters
  2. System initialization
  3. Bluetooth stack event handlers
  4. Bluetooth Mesh-specific initialization

The Mesh Application library takes care of the state machines and event handlers for most of the Bluetooth Mesh functionality. It acts as an interface between Mesh Core libraries and user application (code examples). Hooks are provided by the Mesh application library for the user application to register hardware-specific and implementation-specific callback functions, which are described in Application Callback Functions.

System Bluetooth Parameters

Code 24. wiced_bt_cfg: Application Configuration Structure

 * wiced_bt core stack configuration
 ****************************************************************************/
wiced_bt_cfg_settings_t wiced_bt_cfg_settings =
{
    .device_name                         = (uint8_t *)"Mesh",                                        // Local device name (NULL terminated)
    .device_class                        = { 0x20, 0x07, 0x04 },                                     // Local device class
    .security_requirement_mask           = BTM_SEC_NONE,                                             // Security requirements mask (BTM_SEC_NONE, or 
                                      combinination of BTM_SEC_IN_AUTHENTICATE, BTM_SEC_OUT_AUTHENTICATE, BTM_SEC_ENCRYPT (see #wiced_bt_sec_level_e))
    .max_simultaneous_links              = 3,                                                        // Maximum number simultaneous links to different  
devices

    .br_edr_scan_cfg =                                                                               // BR/EDR scan settings
    {
        .inquiry_scan_type               = BTM_SCAN_TYPE_STANDARD,                                   // Inquiry scan type (BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED)
        .inquiry_scan_interval           = WICED_BT_CFG_DEFAULT_INQUIRY_SCAN_INTERVAL,               // Inquiry scan interval  (0 to use default)
        .inquiry_scan_window             = WICED_BT_CFG_DEFAULT_INQUIRY_SCAN_WINDOW,                 // Inquiry scan window (0 to use default)

        .page_scan_type                  = BTM_SCAN_TYPE_STANDARD,                                   // Page scan type (BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED)
        .page_scan_interval              = WICED_BT_CFG_DEFAULT_PAGE_SCAN_INTERVAL,                  // Page scan interval  (0 to use default)
        .page_scan_window                = WICED_BT_CFG_DEFAULT_PAGE_SCAN_WINDOW                     // Page scan window (0 to use default)
    },

    .ble_scan_cfg =                                                                                  // BLE scan settings
    {
        .scan_mode                       = BTM_BLE_SCAN_MODE_PASSIVE,                                // BLE scan mode (BTM_BLE_SCAN_MODE_PASSIVE, BTM_BLE_SCAN_MODE_ACTIVE, or BTM_BLE_SCAN_MODE_NONE) 

        .high_duty_scan_interval         = 96,             // High duty scan interval
        .high_duty_scan_window           = 96,               // High duty scan window
        .high_duty_scan_duration         = 0,                                                        // High duty scan duration in seconds (0 for infinite)

        .low_duty_scan_interval          = 96,                                                       // Low duty scan interval
        .low_duty_scan_window            = 96,                                                       // Low duty scan window
        .low_duty_scan_duration          = 0,                                                        // Low duty scan duration in seconds (0 for infinite)

        /* Connection scan intervals */
        .high_duty_conn_scan_interval    = WICED_BT_CFG_DEFAULT_HIGH_DUTY_CONN_SCAN_INTERVAL,        // High duty cycle connection scan interval
        .high_duty_conn_scan_window      = WICED_BT_CFG_DEFAULT_HIGH_DUTY_CONN_SCAN_WINDOW,          // High duty cycle connection scan window
        .high_duty_conn_duration         = 30,                                                       // High duty cycle connection duration in seconds (0 for infinite)

        .low_duty_conn_scan_interval     = WICED_BT_CFG_DEFAULT_LOW_DUTY_CONN_SCAN_INTERVAL,         // Low duty cycle connection scan interval
        .low_duty_conn_scan_window       = WICED_BT_CFG_DEFAULT_LOW_DUTY_CONN_SCAN_WINDOW,           // Low duty cycle connection scan window
        .low_duty_conn_duration          = 30,                                                       // Low duty cycle connection duration in seconds (0 for infinite)

        /* Connection configuration */
        .conn_min_interval               = WICED_BT_CFG_DEFAULT_CONN_MIN_INTERVAL,                    // Minimum connection interval, 112 * 1.25 = 140ms.
        .conn_max_interval               = WICED_BT_CFG_DEFAULT_CONN_MAX_INTERVAL,                    // Maximum connection interval, 128 * 1.25 = 160ms.
        .conn_latency                    = WICED_BT_CFG_DEFAULT_CONN_LATENCY,                         // Connection latency, ~1sec
        .conn_supervision_timeout        = WICED_BT_CFG_DEFAULT_CONN_SUPERVISION_TIMEOUT              // Connection link supervsion timeout
    },

    /* BLE advertisement settings */
    {
        .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 48 *0.625 = 30ms
        .high_duty_max_interval          = WICED_BT_CFG_DEFAULT_HIGH_DUTY_ADV_MAX_INTERVAL,          // High duty undirected connectable maximum advertising interval
        .high_duty_duration              = 30,                                                       // High duty undirected connectable advertising duration in seconds (0 for infinite)

        .low_duty_min_interval           = 1024,                                                     // Low duty undirected connectable minimum advertising interval. 2048 *0.625 = 1.28s
        .low_duty_max_interval           = 1024,                                                     // Low duty undirected connectable maximum advertising interval
        .low_duty_duration               = 60,                                                       // Low duty undirected connectable advertising duration in seconds (0 for infinite)

        .high_duty_directed_min_interval = WICED_BT_CFG_DEFAULT_HIGH_DUTY_DIRECTED_ADV_MIN_INTERVAL, // High duty directed connectable minimum advertising interval
        .high_duty_directed_max_interval = WICED_BT_CFG_DEFAULT_HIGH_DUTY_DIRECTED_ADV_MAX_INTERVAL, // High duty directed connectable maximum advertising interval

        .low_duty_directed_min_interval  = WICED_BT_CFG_DEFAULT_LOW_DUTY_DIRECTED_ADV_MIN_INTERVAL,  // Low duty directed connectable minimum advertising interval
        .low_duty_directed_max_interval  = WICED_BT_CFG_DEFAULT_LOW_DUTY_DIRECTED_ADV_MAX_INTERVAL,  // Low duty directed connectable maximum advertising interval
        .low_duty_directed_duration      = 30,                                                       // Low duty directed connectable advertising duration in seconds (0 for infinite)

        .high_duty_nonconn_min_interval  = WICED_BT_CFG_DEFAULT_HIGH_DUTY_NONCONN_ADV_MIN_INTERVAL,  // High duty non-connectable minimum advertising interval
        .high_duty_nonconn_max_interval  = WICED_BT_CFG_DEFAULT_HIGH_DUTY_NONCONN_ADV_MAX_INTERVAL,  // High duty non-connectable maximum advertising interval
        .high_duty_nonconn_duration      = 30,                                                       // High duty non-connectable advertising duration in seconds (0 for infinite)

        .low_duty_nonconn_min_interval   = WICED_BT_CFG_DEFAULT_LOW_DUTY_NONCONN_ADV_MIN_INTERVAL,   // Low duty non-connectable minimum advertising interval
        .low_duty_nonconn_max_interval   = WICED_BT_CFG_DEFAULT_LOW_DUTY_NONCONN_ADV_MAX_INTERVAL,   // Low duty non-connectable maximum advertising interval
        .low_duty_nonconn_duration       = 0                                                         // Low duty non-connectable advertising duration in seconds (0 for infinite)
    },

    .gatt_cfg =                                                                                      // GATT configuration
    {
        .appearance                     = APPEARANCE_GENERIC_TAG,                                    // GATT appearance (see gatt_appearance_e)
        .client_max_links               = 1,                       // Client config: maximum number of servers that local client can connect to
        .server_max_links               = 1,                       // Server config: maximum number of remote clients connections allowed by the local
        .max_attr_len                   = 357,                     // Maximum attribute length; gki_cfg must have a corresponding buffer pool that can 
                                                                     hold this length
#if ( defined(CYW20719B0) || defined(CYW20719B1) || defined(CYW20721B1) || defined(CYW43012C0) || defined(CYW20735B1)  || defined(CYW20819A1) )
        .max_mtu_size                   = 360                    // Maximum MTU size for GATT connections, should be between 23 and (max_attr_len + 5)
#endif
},

    .rfcomm_cfg =                                                                                    // RFCOMM configuration
    {
        .max_links                      = 0,                                     // Maximum number of simultaneous connected remote devices*/
        .max_ports                      = 0                                                          // Maximum number of simultaneous RFCOMM ports
    },

    .l2cap_application =                                                         // Application managed l2cap protocol configuration
    {
        .max_links                      = 0,                                     // Maximum number of application-managed l2cap links (BR/EDR and LE)

        /* BR EDR l2cap configuration */
        .max_psm                        = 0,                                                  // Maximum number of application-managed BR/EDR PSMs
        .max_channels                   = 0,                                                  // Maximum number of application-managed BR/EDR channels

        /* LE L2cap connection-oriented channels configuration */
        .max_le_psm                     = 0,                                                     // Maximum number of application-managed LE PSMs
        .max_le_channels                = 0,                                                     // Maximum number of application-managed LE channels
#if ( defined(CYW20719B1) || defined(CYW20721B1) || defined(CYW43012C0) || defined(CYW20735B1) || defined (CYW20819A1) )
        /* LE L2cap fixed channel configuration */
        .max_le_l2cap_fixed_channels    = 0                                                            // Maximum number of application managed fixed channels supported (in addition to mandatory channels 4, 5 and 6).
#endif
    },

    .avdt_cfg =                                                                                      // Audio/Video Distribution configuration
    {
        .max_links                      = 0,                                                         // Maximum simultaneous audio/video links
    },

    {
        .roles                          = 0,                                                         // Mask of local roles supported (AVRC_CONN_INITIATOR|AVRC_CONN_ACCEPTOR)
        .max_links                      = 0                                                          // Maximum simultaneous remote control links
    },
    .addr_resolution_db_size            = 5,                                                         // LE Address Resolution DB settings - effective only for pre 4.2 controller
#if ( defined(CYW20719B0) || defined(CYW20719B1) || defined(CYW20721B1) || defined(CYW43012C0) || defined(CYW20735B1) || defined(CYW20819A1) )
    .max_number_of_buffer_pools         = 4,                                                         // Maximum number of buffer pools in p_btm_cfg_buf_pools and by wiced_create_pool
    .rpa_refresh_timeout                = 0,                                                         // Interval of  random address refreshing - secs
#if ( defined(CYW43012C0) || defined(CYW20735B1) || defined(CYW20819A1) )
    .ble_white_list_size                = 0                                   // Maximum number of white list devices allowed. Cannot be more than 128
#endif
#else
    .max_mtu_size                       = 360                     // Maximum MTU size for GATT connections, should be between 23 and (max_attr_len + 5)
#endif
};

/*****************************************************************************
 * wiced_bt  buffer pool configuration
 *
 * Configure buffer pools used by the stack  according to application's requirement
 *
 * Pools must be ordered in increasing buf_size.
 * If a pool runs out of buffers, the next  pool will be used
 *****************************************************************************/
const wiced_bt_cfg_buf_pool_t wiced_bt_cfg_buf_pools[WICED_BT_CFG_NUM_BUF_POOLS] =
{
/*  { buf_size, buf_count } */
    { 64,  42 },      /* Small Buffer Pool */
    { 140, 20 },      /* Medium Buffer Pool (used for HCI & RFCOMM control messages, min recommended size is 360) */
    { 360, 12 },      /* Large Buffer Pool  (used for HCI ACL messages) */
    { 1024, 3 },      /* Extra Large Buffer Pool - Used for avdt media packets and miscellaneous (if not needed, set buf_count to 0) */
};

Before looking at the application initialization routines, let’s look at wiced_bt_cfg.c. The configuration structures in this file allow simple control over advertisement/scan parameters for BLE and allocates buffer pools for the stack. The SDK provides APIs that allow the user to modify the settings based on the user’s requirements. The default values provided in this file case be used as-is for Mesh implementations. Typically, the only parameter which needs modification for a Mesh application is the device name, because it is unique for each application. The device name parameter, wiced_bt_cfg.settings.device_name, can be modified in the user application code so it is not necessary to change it in wiced_bt_cfg.c.

For example, if a user is creating a Dimmable Light Mesh application, the device name can be modified in the user application code in the Mesh initialization function as follows:

wiced_bt_cfg_settings.device_name = (uint8_t *)"Dimmable Light";

All the parameters in this file are tuned for optimal performance of the Mesh device. So, it is recommended not to make any modification to this file.

System Initialization

APPLICATION_START() Function

Code 25. mesh_app_hci.c: Initializing Transport for Printing Debug Information


void mesh_app_hci_init(void)
{
#ifndef MESH_HOMEKIT_COMBO_APP
    wiced_transport_init(&transport_cfg);

    // create special pool for sending data to the MCU
    host_trans_pool = wiced_transport_create_buffer_pool(1024, 2);
#endif

#ifdef WICED_BT_TRACE_ENABLE
#ifndef _DEB_ENABLE_HCI_TRACE
    //For the 24 MHz board set the UART type as WICED_ROUTE_DEBUG_TO_PUART
    // For BCM920706V2_EVAL board make sure SW5.2 and SW5.4 are ON and all other SW5 are off
    wiced_set_debug_uart(WICED_ROUTE_DEBUG_TO_PUART);
#if (defined(CYW20706A2) || defined(CYW20735B0) || defined(CYW20719B0) || defined(CYW43012C0))
    wiced_hal_puart_select_uart_pads(WICED_PUART_RXD, WICED_PUART_TXD, 0, 0);
#endif
#ifndef CYW20706A2
    wiced_hal_puart_set_baudrate(921600);
#endif
#else
    // 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

    /* Starting the app timer  */
    memset(&app_timer, 0, sizeof(wiced_timer_t));
    if (wiced_init_timer(&app_timer, mesh_app_timer, 0, WICED_SECONDS_PERIODIC_TIMER) == WICED_SUCCESS)
    {
        if (wiced_start_timer(&app_timer, MESH_APP_TIMEOUT_IN_SECONDS) != WICED_SUCCESS)
        {
            WICED_BT_TRACE("APP START Timer FAILED!!\n");
        }
    }
    else
    {
        WICED_BT_TRACE("APP INIT Timer FAILED!!\n");
    }
#endif
    wiced_bt_dev_register_hci_trace(mesh_hci_trace_cback);
}

Code 26. mesh_app_timer.c: Timer Callback Function

void mesh_app_timer(uint32_t arg)
{
    static uint32_t app_timer_count = 1;
    app_timer_count++;

#ifdef _DEB_PRINT_BUF_USE
    /* dump wiced bt buffer statistics on every 10 seconds to monitor buffer usage */
    if (!(app_timer_count % _DEB_PRINT_BUF_USE))
    {
        _deb_print_buf_use();
    }
#endif
#ifdef _DEB_PRINT_MESH_STATS
    // dump mesh statistics on every _DEB_PRINT_MESH_STATS
    if ((app_timer_count % _DEB_PRINT_MESH_STATS) == 2)
    {
        _deb_print_mesh_stats();
    }
#endif
}

The first visible entry point in to the Mesh application is the APPLICATION_START() function shown in Code 30. When the Mesh device starts up, it enters the APPLICATION_START() function located in mesh_application.c. This file is located at CODE_EXAMPLE_NAME _mainapp/libraries/mesh_app_lib.

The APPLICATION_START() function performs the following critical tasks:

wiced_bt_stack_init(mesh_management_cback, &wiced_bt_cfg_settings, wiced_bt_cfg_buf_pools)

The user application code defines callback functions in the wiced_bt_mesh_app_func_table structure if it is required to perform hardware-specific initialization and develop custom application logic. If a hardware initialization function is defined, the user application code takes care of the hardware initialization; otherwise, the default initialization is completed based on the hardware/schematic of the Cypress evaluation kit. Code 30 shows the initialization performed in APPLICATION_START(). The following sections provide more detailed descriptions of each process in this function.

  1. The transport method and related parameters are initialized in the mesh_app_hci_init() function. In the case of Mesh code examples, the default configuration is PUART with a baud rate of 921600 bps. The application debug information is sent over this interface. The baud rate can be configured using the wiced_hal_puart_set_baudrate() function as shown in Code 25. The mesh_app_hci_init function is defined in the mesh_app_hci.c file that is located under the following location:

    CODE_EXAMPLE_NAME\bt_20819A1-1.0\components\BT-SDK\common\libraries\mesh_app_lib\ mesh_app_hci.c

A periodic one-second timer is initialized and started in the mesh_app_hci_init() function. Existing code in the timer callback function, mesh_app_timer, has a provision to transmit the buffer usage data and Mesh status data every 30 seconds over the PUART interface.

Code 27. mesh_application.c: Hardware Initialization Function

    if (wiced_bt_mesh_app_func_table.p_mesh_app_hw_init != NULL)
    {
        wiced_bt_mesh_app_func_table.p_mesh_app_hw_init();
    }
    else
    {
        /* Configure buttons available on the platform */
#if defined(CYW20706A2)
        wiced_hal_gpio_configure_pin(WICED_GPIO_BUTTON, WICED_GPIO_BUTTON_SETTINGS(GPIO_EN_INT_BOTH_EDGE), WICED_GPIO_BUTTON_DEFAULT_STATE);
        wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_BUTTON, mesh_interrupt_handler, NULL);
#elif (defined(CYW20735B0) || defined(CYW20719B0) || defined(CYW20721B0))
        wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_PIN_BUTTON, mesh_interrupt_handler, NULL);
        wiced_hal_gpio_configure_pin(WICED_GPIO_PIN_BUTTON, WICED_GPIO_BUTTON_SETTINGS, GPIO_PIN_OUTPUT_LOW);
#else
        wiced_platform_register_button_callback(WICED_PLATFORM_BUTTON_1, mesh_interrupt_handler, NULL, GPIO_EN_INT_BOTH_EDGE);
#endif
    }

2.The Mesh Application library provides hooks for the Mesh user application code to register callback functions. Callback functions applicable/needed by the Mesh user application code should be populated in the wiced_bt_mesh_app_func_table structure so that the Mesh Application library knows that the user application code wants to perform custom hardware configuration instead of the default configuration in the Mesh Application library as shown in Code 27.

For example, if the application project requires the use of a specific button, an entry should be added in wiced_bt_mesh_app_func_table as shown in Code 28. By doing this, the Mesh Application library knows that the application project is required to customize the implementation based on user requirements; it will not rely on the default button configuration in the Mesh Application library.

Code 28. BLE_Mesh_Dimmer_mainapp: Custom Hardware Initialization Function button_hardware_init

/*
 * Mesh application library will call into application functions if provided by the application.
 */
wiced_bt_mesh_app_func_table_t wiced_bt_mesh_app_func_table =
{
    mesh_app_init,          // application initialization
    button_hardware_init,   // hardware initialization
    NULL,                   // GATT connection status
    NULL,                   // attention processing
    NULL,                   // notify period set
    NULL                    // WICED HCI command
};

Code 29. mesh_application.c: Setup NVRAM IDs for Mesh Parameters

void mesh_setup_nvram_ids()
{
    uint16_t cfg_data_len = wiced_bt_mesh_get_node_config_size(&mesh_config);

    wiced_bt_mesh_light_lc_nvram_id_start           = WICED_NVRAM_VSID_END   - number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_LIGHT_LC_SRV);
    wiced_bt_mesh_light_hsl_nvram_id_start          = wiced_bt_mesh_light_lc_nvram_id_start - 
                                                                     number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_LIGHT_HSL_SRV);
    wiced_bt_mesh_light_ctl_nvram_id_start          = wiced_bt_mesh_light_hsl_nvram_id_start        - 
                                                                     number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_LIGHT_CTL_SRV);
    wiced_bt_mesh_light_xyl_nvram_id_start          = wiced_bt_mesh_light_ctl_nvram_id_start        -  
                                                                     number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_LIGHT_XYL_SRV);
    wiced_bt_mesh_light_lightness_nvram_id_start    = wiced_bt_mesh_light_xyl_nvram_id_start        - 
                                                                      number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_LIGHT_LIGHTNESS_SRV);
    wiced_bt_mesh_power_level_nvram_id_start        = wiced_bt_mesh_light_lightness_nvram_id_start  -  
                                                                    number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_GENERIC_POWER_LEVEL_SRV);
    wiced_bt_mesh_power_onoff_nvram_id_start        = wiced_bt_mesh_power_level_nvram_id_start      - 
                                                                    number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_GENERIC_POWER_ONOFF_SRV);
    wiced_bt_mesh_default_trans_time_nvram_id_start = wiced_bt_mesh_power_onoff_nvram_id_start      - 1;
    wiced_bt_mesh_scheduler_nvram_id_start          = wiced_bt_mesh_default_trans_time_nvram_id_start - wiced_bt_mesh_scheduler_events_max_num;
    wiced_bt_mesh_scene_nvram_id_end                = wiced_bt_mesh_scheduler_nvram_id_start        - 1;
    wiced_bt_mesh_scene_nvram_id_start              = wiced_bt_mesh_scene_nvram_id_end              - wiced_bt_mesh_scene_max_num;         
    wiced_bt_mesh_scene_register_nvram_id           = wiced_bt_mesh_scene_nvram_id_start            - 1;        

    wiced_bt_mesh_core_nvm_idx_node_data            = wiced_bt_mesh_scene_register_nvram_id     - 1;
    wiced_bt_mesh_core_nvm_idx_virt_addr            = wiced_bt_mesh_core_nvm_idx_node_data      - 1;
    wiced_bt_mesh_core_nvm_idx_frnd_state           = wiced_bt_mesh_core_nvm_idx_virt_addr      - 1;
    wiced_bt_mesh_core_nvm_idx_net_key_begin        = wiced_bt_mesh_core_nvm_idx_frnd_state     - wiced_bt_mesh_core_net_key_max_num;
    wiced_bt_mesh_core_nvm_idx_app_key_begin        = wiced_bt_mesh_core_nvm_idx_net_key_begin  - wiced_bt_mesh_core_app_key_max_num;
    wiced_bt_mesh_core_nvm_idx_health_state         = wiced_bt_mesh_core_nvm_idx_app_key_begin  - 1;
    wiced_bt_mesh_core_nvm_idx_cfg_data             = wiced_bt_mesh_core_nvm_idx_health_state   - ((cfg_data_len + 0xfe) / 0xff);
    mesh_nvm_idx_seq                                = wiced_bt_mesh_core_nvm_idx_cfg_data       - 1;

    WICED_BT_TRACE("setup nvram ids: net_key_max_num:%d app_key_max_num:%d nvm_idx_seq:%x %x-%x\n", wiced_bt_mesh_core_net_key_max_num, wiced_bt_mesh_core_app_key_max_num, mesh_nvm_idx_seq, wiced_bt_mesh_core_nvm_idx_cfg_data, WICED_NVRAM_VSID_END);
}

3.The Bluetooth stack is initialized by calling the wiced_bt_stack_init function.

As part of the wiced_bt_stack_init function, Bluetooth configuration settings, wiced_bt_cfg_settings, are passed to the stack and the mesh_management_cback function is registered to receive BLE stack events. Note that mesh_management_cback function already exists and does not need to be added to your source file. The wiced_bt_stack_init function is declared in the wiced_bt_stack.h standard SDK library that is in the include folder of the project. The actual implementation of this function is in ROM.

4.Maximum number of network keys, application keys, scenes and scheduler events are configured to 4, 8, 10 and 16 respectively. The maximum values for these parameters depend on the available free RAM for a given applicaiton.

Code 30. APPLICATION_START: Stack Initialization is ROM-Driven Initialization

/*
*  Entry point to the application. Set device configuration and start BT
*  stack initialization.  The actual application initialization will happen
*  when stack reports that BT device is ready.
*/
#ifndef MESH_HOMEKIT_COMBO_APP
#if (defined(CYW20719B0) || defined(CYW20719B1) || defined(CYW20721B1) ||  defined(CYW20706A2))
APPLICATION_START()
#else
void application_start(void)
#endif
#else // MESH_HOMEKIT_COMBO_APP
void mesh_application_start()
#endif
{
    mesh_app_hci_init();

    // If application wants to control the hardware, call appropriate initialization function.  
    // Otherwise use default processing of the mesh application library.
    if (wiced_bt_mesh_app_func_table.p_mesh_app_hw_init != NULL)
    {
        wiced_bt_mesh_app_func_table.p_mesh_app_hw_init();
    }
    else
    {
        /* Configure buttons available on the platform */
#if defined(CYW20706A2)
        wiced_hal_gpio_configure_pin(WICED_GPIO_BUTTON, WICED_GPIO_BUTTON_SETTINGS(GPIO_EN_INT_BOTH_EDGE), WICED_GPIO_BUTTON_DEFAULT_STATE);
        wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_BUTTON, mesh_interrupt_handler, NULL);
#elif (defined(CYW20735B0) || defined(CYW20719B0) || defined(CYW20721B0))
        wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_PIN_BUTTON, mesh_interrupt_handler, NULL);
        wiced_hal_gpio_configure_pin(WICED_GPIO_PIN_BUTTON, WICED_GPIO_BUTTON_SETTINGS, GPIO_PIN_OUTPUT_LOW);
#else
        wiced_platform_register_button_callback(WICED_PLATFORM_BUTTON_1, mesh_interrupt_handler, NULL, GPIO_EN_INT_BOTH_EDGE);
#endif
    }
#ifndef MESH_HOMEKIT_COMBO_APP
    // Register call back and configuration with stack
    wiced_bt_stack_init(mesh_management_cback, &wiced_bt_cfg_settings, wiced_bt_cfg_buf_pools);
#endif

    // Currently we can support up to 4 network keys.
    wiced_bt_mesh_core_net_key_max_num = 4;
    wiced_bt_mesh_core_app_key_max_num = 8;
    wiced_bt_mesh_scene_max_num            = 10;
    wiced_bt_mesh_scheduler_events_max_num = 16; // PTS test uses index 15 (MMDL/SR/SCHS/BV-01-C )

    // setup NVRAM IDs which will be used by core and models
    mesh_setup_nvram_ids();

    WICED_BT_TRACE("Mesh Start\n");
}

Bluetooth Stack Event Handler

Code 31. mesh_application.c: Bluetooth Stack Callback Events

wiced_result_t mesh_management_cback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data)
{
    wiced_bt_ble_advert_mode_t          *p_mode;
    wiced_result_t                      result = WICED_BT_SUCCESS;

    // WICED_BT_TRACE("mesh_management_cback: %x\n", event);
    //test_aes();

    switch (event)
    {
        /* Bluetooth  stack enabled */
    case BTM_ENABLED_EVT:
#ifdef _DEB_DELAY_START_SEC
        mesh_delay_start_init();
#else
#ifdef MESH_APPLICATION_MCU_MEMORY
        mesh_application_send_hci_event(HCI_CONTROL_EVENT_DEVICE_STARTED, NULL, 0);
#else
        mesh_application_init();
#endif
#endif
        break;

    case BTM_DISABLED_EVT:
        break;

    case BTM_BLE_ADVERT_STATE_CHANGED_EVT:
        p_mode = &p_event_data->ble_advert_state_changed;
        WICED_BT_TRACE("Advertisement State Changed:%d\n", *p_mode);
        if (*p_mode == BTM_BLE_ADVERT_OFF)
        {
            WICED_BT_TRACE("adv stopped\n");
            // On failed attempt to connect FW stops all connectable adverts. 20719B1 also receives that event in case of successfull connection
            // If we disconnected then notify core to restart them
            if (!mesh_app_gatt_is_connected())
            {
                wiced_bt_mesh_core_connection_status(0, WICED_FALSE, 0, 20);
            }
        }
        break;

    case BTM_BLE_SCAN_STATE_CHANGED_EVT:
        WICED_BT_TRACE("Scan State Change:%d\n", p_event_data->ble_scan_state_changed);
        break;

    case  BTM_PAIRED_DEVICE_LINK_KEYS_REQUEST_EVT:
        result = WICED_BT_ERROR;
        break;

    default:
        break;
    }

    return result;
}

The Bluetooth event handler function, mesh_management_cback, is registered during initialization to receive Bluetooth stack-related callback events. Two Bluetooth events are of interest for a Mesh application:

  1. The BTM_ENABLED_EVT event is triggered after Bluetooth stack initialization is successful. The Bluetooth Mesh library initialization and necessary callback function registration are done in this event.
  2. The BTM_BLE_ADVERT_STATE_CHANGED_EVT event is received after an advertisement timeout period or after a successful connection. In this event, the Mesh Core is requested to restart advertisements if the Mesh device is in a disconnected state.

Mesh Core Initialization Structure

Code 32. Bluetooth GATT Callback Registration

void mesh_app_gatt_init(void)
{
    wiced_bt_gatt_status_t gatt_status;
#ifndef MESH_HOMEKIT_COMBO_APP
    /* Register with stack to receive GATT callback */
    gatt_status = wiced_bt_gatt_register(mesh_gatts_callback);
    WICED_BT_TRACE("wiced_bt_gatt_register: %d\n", gatt_status);
    memset(&mesh_gatt_cb, 0, sizeof(mesh_gatt_cb_t));
#endif // MESH_HOMEKIT_COMBO_APP
}

Code 33. Generate BD Address for Provisioned and Non-Provisioned State and UUID

   if (mesh_nvram_access(WICED_FALSE, NVRAM_ID_LOCAL_ADDR, buffer, (2 * 6) + 16, &result) != ((2 * 6) + 16))
    {
        mesh_application_gen_bda(init.non_provisioned_bda, init.provisioned_bda, init.device_uuid, WICED_TRUE);
    }
    else
    {
        memcpy(init.non_provisioned_bda, &buffer[0], 6);
        memcpy(init.provisioned_bda, &buffer[6], 6);
        memcpy(init.device_uuid, &buffer[6 * 2], 16);
    }

Code 34. Mesh Application Initialization Function

{
    wiced_result_t            result;
    uint8_t                   buffer[(6 * 2) + 16];
    wiced_bt_mesh_core_init_t init = { 0 };

    WICED_BT_TRACE("## mesh_application_init free_bytes:%d ##\n", wiced_memory_get_free_bytes());

#ifndef MESH_HOMEKIT_COMBO_APP
    /* Initialize wiced app */
#if (!defined(CYW20735B1) && !defined(CYW20819A1))
    wiced_bt_app_init();
#endif

#endif

#ifndef MESH_HOMEKIT_COMBO_APP
    mesh_app_gatt_init();
    wiced_bt_set_pairable_mode(WICED_FALSE, WICED_FALSE);
#endif // MESH_HOMEKIT_COMBO_APP

    //remember if we are provisioner (config client)
    mesh_config_client = number_of_elements_with_model(WICED_BT_MESH_CORE_MODEL_ID_CONFIG_CLNT) > 0 ? WICED_TRUE : WICED_FALSE;

#ifdef PTS
    // initialize core
    // each node shall be assigned a 128-bit UUID known as the Device UUID.
    // Device manufacturers shall follow the standard UUID format and generation
    // procedure to ensure the uniqueness of each Device UUID.
    // for now device_uuid is local bda with hardcoded(0x0f) remaining bytes
    wiced_bt_dev_read_local_addr(init.non_provisioned_bda);
#ifdef _DEB_DF_TEST_BDA
    // remember local BD address for DF test mode
    memcpy(_deb_df_test_bda, init.non_provisioned_bda, 6);
#endif
    memcpy(init.provisioned_bda, init.non_provisioned_bda, sizeof(wiced_bt_device_address_t));
    memcpy(&init.device_uuid[0], init.non_provisioned_bda, 6);
    memset(&init.device_uuid[6], 0x0f, 16 - 6);
    // in PTS disable proxy on demand - always advertyse proxy service network if when appropriate
    wiced_bt_mesh_core_proxy_on_demand_advert_to = 0;
#else
    // We currently use 2 BDAs, one for the initial scenario. We also keep saved UUID
    if (mesh_nvram_access(WICED_FALSE, NVRAM_ID_LOCAL_ADDR, buffer, (2 * 6) + 16, &result) != ((2 * 6) + 16))
    {
        mesh_application_gen_bda(init.non_provisioned_bda, init.provisioned_bda, init.device_uuid, WICED_TRUE);
    }
    else
    {
        memcpy(init.non_provisioned_bda, &buffer[0], 6);
        memcpy(init.provisioned_bda, &buffer[6], 6);
        memcpy(init.device_uuid, &buffer[6 * 2], 16);
    }
#endif

    // Remove this line if MeshClient supports proxy on demand
    wiced_bt_mesh_core_proxy_on_demand_advert_to = 0;

#ifdef MESH_SUPPORT_PB_GATT
    mesh_config.features |= WICED_BT_MESH_CORE_FEATURE_BIT_PB_GATT;
#endif
    init.p_config_data = &mesh_config;
    init.callback = get_msg_handler_callback;
    init.pub_callback = mesh_publication_callback;
    init.proxy_send_callback = mesh_app_proxy_gatt_send_cb;
    init.nvram_access_callback = mesh_nvram_access;
    init.fault_test_cb = mesh_fault_test;
    init.attention_cb = wiced_bt_mesh_app_func_table.p_mesh_app_attention;
    init.state_changed_cb = mesh_state_changed_cb;
    init.scan_callback = mesh_start_stop_scan_callback;
    node_authenticated = WICED_BT_SUCCESS == wiced_bt_mesh_core_init(&init);

    mesh_app_gatt_db_init(node_authenticated);

    // Initialize own SEQ and RPL
    if (!mesh_application_seq_init())
        mesh_application_factory_reset();

    // Initialize OTA FW upgrade
    if (!wiced_ota_fw_upgrade_init(NULL, mesh_ota_firmware_upgrade_status_callback, mesh_ota_firmware_upgrade_send_data_callback))
    {
        WICED_BT_TRACE("mesh_application_init: wiced_ota_fw_upgrade_init failed\n");
    }

    wiced_bt_mesh_app_provision_server_init(pb_priv_key, NULL);

    mesh_app_gatt_init();

    if (wiced_bt_mesh_app_func_table.p_mesh_app_init)
    {
        wiced_bt_mesh_app_func_table.p_mesh_app_init(node_authenticated);
    }
    // Now start mesh picking up tx power set by app in wiced_bt_mesh_core_adv_tx_power
    wiced_bt_mesh_core_start();

    WICED_BT_TRACE("***** Free mem after app_init:%d\n", wiced_memory_get_free_bytes());
}

The mesh_application_init() function is executed in the BTM_ENABLED_EVT event of the Bluetooth stack callback.

All Mesh-specific initialization occurs in this function. Detailed steps in this function are provided below and can be seen in Code 34.

  1. Register a callback function, mesh_gatts_callback in mesh_app_init(), to receive Bluetooth GATT events.
  2. Disable the standard Bluetooth pairing capability by using wiced_bt_set_pairable_mode(WICED_FALSE, WICED_FALSE).
  3. Check whether the Mesh device has Configuration Client Model and set a flag, mesh_config_client, accordingly. The Configuration Client model is used only in the Provisioner code example. This flag is set to ‘false’ for all other use cases.
  4. A Mesh device needs two random static Bluetooth device addresses; one is used during non-provisioned state and the other is used after the device is provisioned into a network. A Mesh device also needs a 128-bit (16-byte) UUID for virtual addresses. The generation of the Bluetooth device addresses and UUID values for the Mesh device occur when the device boots up for the very first time. These addresses and UUID are stored in the NVRAM. These addresses are retrieved from the NVRAM during subsequent power cycles and stored in local variables.
  5. Initialize the Mesh Core with the necessary parameters/structures/callback functions. Most of the necessary functions are implemented in mesh_application.c with a few exceptions with respect to configuration structures and user-specific functions. The Mesh Core initialization is described in more detail in Mesh Core Initialization Structure below.
  6. Initialize the GATT database based on the status of the device (provisioned or non-provisioned) using the function mesh_app_gatt_db_init(node_authenticated). The GATT database of a Mesh device consists of multiple services like provisioning service, OTA service, proxy service, Device information service etc. The difference between provisioned and non-provisioned GATT data base is:
  7. The provisioning service is enabled in the GATT database when the device is unprovisioned (gatt_db_unprovisioned[]).
  8. The proxy service (if the node supports proxy feature) and mesh command service are enabled in the GATT database when the device is provisioned (gatt_db_provisioned[]).
  9. Initialize the sequence number and RPL (Replay Protection List) list with mesh_application_seq_init. The sequence number and RPL are initialized to ‘0’ and stored in NVRAM if the device is not provisioned; else the sequence number is updated and stored in NVRAM.
  10. Initialize the firmware update library using the wiced_ota_fw_upgrade_init function.
  11. Perform the Mesh application initialization defined in the application function, wiced_bt_mesh_app_func_table.p_mesh_app_init(node_authenticated). Each code example (user application code) implements its own wiced_bt_mesh_app_func_table. Based on the configurations contained in wiced_bt_mesh_app_func_table, the appropriate functions are initialized and executed.
  12. Call the Mesh Start function, wiced_bt_mesh_core_start(), after all of the above initializations are performed successfully.

Mesh Core Initialization Structure

Code 35. Definition of wiced_bt_mesh_init_t structure

typedef struct
{
    uint8_t device_uuid[16];                                   /**< 128-bit Device UUID. Device manufacturers shall follow the standard UUID format 
                                                                    and generation procedure to ensure the uniqueness of each Device UUID */
    uint8_t non_provisioned_bda[6];                             /**< BD address in non-provisioned state */
    uint8_t provisioned_bda[6];                                 /**< BD address in provisioned state */
    wiced_bt_mesh_core_config_t *p_config_data;                 /**< Configuration data */
    wiced_bt_mesh_core_get_msg_handler_callback_t callback;     /**< Callback function to be called by the Core at received message to get message                                                                            
                                                                     handler */
    wiced_bt_mesh_core_publication_callback_t pub_callback;     /**< Callback function to be called by the Core at time when publication is required by 
                                                                     periodic publication or when configuration changes */
    wiced_bt_mesh_core_scan_callback_t scan_callback;           /**< Callback function to be called by the Core when scan needs to be started or  
                                                                     stopped */
    wiced_bt_mesh_core_proxy_send_cb_t proxy_send_callback;     /**< Callback function to send proxy packet over GATT */
    wiced_bt_core_nvram_access_t nvram_access_callback;         /**< Callback function to read/write from/to NVRAM */
    wiced_bt_mesh_core_health_fault_test_cb_t fault_test_cb;    /**< Callback function to be called to invoke a self test procedure of an Element */
    wiced_bt_mesh_core_attention_cb_t attention_cb;             /**< Callback function to be called to attract human attention */
    wiced_bt_mesh_core_state_changed_callback_t state_changed_cb;   /**< Callback function to be called on any change in the mesh state */
} wiced_bt_mesh_core_init_t;

Code 36. Mesh Core Initialization Code Snippet from mesh_applicaiton_init() function

    init.callback = get_msg_handler_callback;
    init.pub_callback = mesh_publication_callback;
    init.proxy_send_callback = mesh_app_proxy_gatt_send_cb;
    init.nvram_access_callback = mesh_nvram_access;
    init.fault_test_cb = mesh_fault_test;
    init.attention_cb = wiced_bt_mesh_app_func_table.p_mesh_app_attention;
    init.state_changed_cb = mesh_state_changed_cb;
    init.scan_callback = mesh_start_stop_scan_callback;
    node_authenticated = WICED_BT_SUCCESS == wiced_bt_mesh_core_init(&init);

As part of the Mesh Core initialization process, the Mesh Application library provides the wiced_bt_mesh_init_t structure as a parameter to the API wiced_bt_mesh_core_init(). The parameters of the wiced_bt_mesh_init_t structure are shown in Code 35, the code snippet from the mesh_applicaiton_init() function that has details of the assigned callback functions and structures is shown in Code 36.

Table 9 provides details of the structures and callback functions that are required as part of the Mesh Core initialization process. These structures and callback functions are assigned to each field of the wiced_bt_mesh_init_t structure which is then passed as a parameter of for wiced_bt_mesh_core_init() to initialize the Mesh Core.

Any structure or callback function that is defined in the User Application Code (column 2 in Table 9) is the responsibility of the developer to define the appropriate configurations/actions to be completed. Any structure or callback function that is defined in the Mesh Application Library is already completed and is not recommended to change (these are provided in Table 9 for information and understanding of the Mesh Core Initiailization process).

Table 9. Mesh Core Initialization Structure

tab1

Appendix B.Sensor Configuration

This appendix provides the sensor configuration parameters available for a Mesh enabled sensor device. Each Mesh device may contain one or more sensors.

The wiced_bt_mesh_core_config_sensor_t structure defines the details of a sensor configuration. Each parameter available in this structure is described below. * property_id: The Sensor Property ID field is a 2-octet value referencing a device property that describes the meaning and the format of data reported by a sensor. The format of this property is Boolean as defined in Mesh Device Properties Specification.

Table 10. .sampling_function Parameter Values (Bluetooth SIG, 2019)

Value Description
0x00 Unspecified
0x01 Instantaneous
0x02 Arithematic Mean
0x03 RMS
0x04 Maximum
0x05 Minimum
0x06 Accumulated(see note below)
0x07 Count (see note below)
0x08-0xFF Reserved for futuren Use

* .measurement_period: This Sensor Measurement Period parameter specifies a value, n, that represents the averaging time span, accumulation time, or measurement period in seconds over which the measurement is taken, using the formula shown below:

Represented value = 1.1<sup>n−64</sup>

For cases where the measurement period is not available, a value 0x00 is assigned to indicate that the sampling function field is unknown or not provided. Valid settings for this parameter are show in below Table 11.

Table 11. .measurement_period Parameter Values (Bluetooth SIG, 2019)

Value n Represented Value Description
0x00 Not Applicable not Applicable
0x01-0xFF 1.1n−64 Time Period in seconds

* .update_interval: The measurement reported by a sensor is internally refreshed at the frequency indicated in the Sensor Update Interval field (e.g., a temperature value that is internally updated every 15 minutes). This field specifies a value, n, that determines the interval (in seconds) between updates, using the formula:

Represented value = 1.1<sup>n−64</sup>

For cases in which the measurement period is not available, the value 0x00 shall be assigned to indicate that the sampling function field is unknown or not provided. Valid settings for this parameter are shown in Table 12.

Table 12. .update_interval Parameter Values (Bluetooth SIG, 2019)

Value n Represented Value Description
0x00 Not Applicable not Applicable
0x01-0xFF 1.1n−64 Update interval in seconds

mesh_sensor_fast_publish_period = mesh_sensor_publish_period / p_sensor->cadence.fast_cadence_period_divisor;

For example, if the mesh_sensor_publish_period is set to 320000 using a Mesh Helper application, then the mesh_sensor_fast_publish_period is 10 seconds (320000 / 32 milliseconds).

* .trigger_type_percentage: The Status Trigger Type field defines the unit and format of the Status Trigger Delta Down and the Status Trigger Delta Up parameters.
• A value of ‘0’ means that the format of the data is as defined by the property_id parameter contained in the sensors element configuration structure.
• A value of ‘1’ means that the unit is «unitless», the format type is set to 0x06 (uint16), and the value is represented as a percentage change with a resolution of 0.01 percent.

* .trigger_delta_down: The Status Trigger Delta Down parameter controls the negative change of a measured quantity that triggers publication of a Sensor Status message. The setting is calculated based on the value of the parmater .trigger_type_percentage.
• If the value of the .trigger_type_percentage parameter is ‘0’, the setting is calculated as defined by the sensors property_id parameter.
• If the value of the .trigger_type_percentage parameter is ‘1’, the setting is calculated using the following formula:

Represented value = .trigger_delta_down/ 100

* .trigger_delta_up: The Status Trigger Delta Up parameter controls the positive change of a measured quantity that triggers publication of a Sensor Status message. The setting is calculated based on the value of the parmater .trigger_type_percentage:
• If the value of the .trigger_type_percentage parameter is ‘0’, the setting is calculated as defined by the sensors property_id parameter.
• If the value of the .trigger_type_percentage parameter is ‘1’, the setting is calculated using the following formula:

Represented value = .trigger_delta_up/ 100

* .min_interval:
The min interval parameter controls the minimum interval between publishing two consecutive sensor status messages. The value is represented as 2n milliseconds.
Min_interval = 2n milliseconds The valid range of n is 0 to 26.

* .fast_cadence_low: The Fast Cadence Low parameter defines the lower boundary of a range of measured quantities when the publishing cadence is increased as defined by the Fast Cadence Period Divisor field. The represented value is calculated as defined by thesensors property_id parameter.

* .fast_cadence_high: The Fast Cadence High parameter defines the upper boundary of a range of measured quantities when the publishing cadence is increased as defined by the Fast Cadence Period Divisor field. The represented value is calculated as defined by the sensors property_id parameter.

Figure 62. Sensor Series Array (Bluetooth SIG, 2019)

Table 13. Sensor .series_columns Parameters (Bluetooth SIG, 2019)

Field Size (octets) Notes
Sensor property ID 2 Property describing the data series of the sensor
Sensor Raw value X Variable Raw value representing the left corner of a column on the X axis
Sensor column Width Variable Raw value representing the width of the column
Sensor Raw value Y Variable Raw value representing the height of the column in the Y axis

Table 13. Sensor .series_columns Parameters (Bluetooth SIG, 2019)

Value Meaning
0x00 Prohibited
0x01 The device property can be read
0x02 Prohibited
0x03 The device property can be writtern
0x04-0xFF Prohibited

Appendix C.iOS Helper App Installation

The iOS Helper app installation has the following requirements:

Figure 63. Xcode IDE with MeshApp and MeshFramework Projects

Figure 64. Xcode Accounts Page

Figure 65. Selecting the iOS MeshApp and the iPhone

  1. A MacBook with the latest version of BT SDK and Xcode IDE installed
  2. An iPhone and a registered Apple ID and password

The latest version of the BT SDK can be found at the ModusToolbox BT SDK community page. For the latest version, download the source code from the GitHub repository.

Once you have acquired all the pieces needed to install the iOS Helper app, follow these steps:

  1. Connect the iPhone to the MacBook using phone’s data cable.
  2. Go to Users/home/ModusToolbox_1.1/libraries/bt_20819A1-1.0/components/BT-SDK/common/apps/ snip/mesh/peerapps/iOS/MeshApp.
  3. Double-click on the “MeshApp.xcworkspace” to open the MeshApp and MeshFramework projects in the Xcode IDE. The opened projects include the MeshApp and MeshFramework shown below.
  4. Click on Xcode > Preferences… in the Xcode menu to open the Preferences dialogue. Select the Accounts item. The Accounts page is like what is shown in Figure 64. Click the + button in the left bottom to add your Apple ID in Xcode, and then input your Apple ID and password to log in. After your Apple ID is added and you have logged in successfully, your Apple ID will be shown as displayed in Figure 64.
  5. Click the MeshApp project on the left of Xcode as shown in Figure 63. Click the General item on the right side to display the Signing configuration.
  6. As shown in Figure 63, enable Automatically manage signing, and then update the Team by selecting your Apple ID in the drop list.
  7. Next, find the Identify configuration above the Signing configuration, and add a unique suffix string to the Build Identifier string, such as changing “com.cypress.le.mesh.MeshApp” to “com.cypress.le.mesh.MeshApp.Tom”. This is needed as the previous Build Identifier string may have been used, so you must use another unique Build Identifier to build and install the iOS MeshApp.
  8. Make sure that the iOS MeshApp and the connected iPhone device have been selected to build and run the app. These selections can be done at the top of the Xcode IDE as shown in Figure 65.
  9. Click Product -> Clean Build Folder in the Xcode menu to clean the build system. Now, the build environment is ready.
  10. Click the icon button on the top left of the Xcode IDE to build and install MeshApp automatically into the connected iPhone device. You will need to set the MacBook as a Trusted device in your iPhone settings, if it is not already done.
  11. When you open the iOS app for the first time, it will require you to enter your Apple ID and Password. After this, your app is ready to create Mesh networks.

Appendix D. Using Android Helper App

For installation instructions and location of the .apk file and source code, see Android Helper App .

Once installed, the app will appear on your phone as “MeshLighting”. When you open the app for the first time, it will ask for following four permissions:

  1. Allow MeshLighting to take pictures and record video?
  2. Allow MeshLighting to access this device’s location?
  3. Allow MeshLighting to access photos, media, and files on your device?
  4. Allow MeshLighting to access your contacts?

Select Allow for all these. If these are not allowed, the app will not work.

Once you have granted the permissions, you are set to use the app to create Mesh networks. The Android app is very intuitive and does not require a detailed user guide. However, the following steps can be referred to while using the app. This section uses Use Case #1 (Mesh network with 1 Dimmer Switch and 3 Dimmable Light Bulbs) in this application note to demonstrate Android app usage.

Figure 66. Creating a Mesh Network

1.Follow the below steps to create a Mesh network.

a. On home screen, tap on the three dots next to Create a room to place your lights, for example, master bedroom.
b. Select Create Network. A new window, New Network, opens where a network can be created. In this case, the network name is assigned as “cypress”. You can use a custom name for your network.
c. Once the name is entered, select OK.
Observe that a new network with the name “cypress” is created.

Figure 67. Creating a Room and Updating the Name

2.Follow these steps to create a group.

a. Tap on the + (Add A GROUP) button located towards the bottom of the app screen.

b. This brings you to a new screen with a default room named “New Room”. To change the room name, select Pencil symbol at the top of the screen.

c. Enter the desired name of the group and tap OK. In this example, the name of the group is “building 6.2”.

d. To save group name and settings, tap Save.

Figure 68. Node Provisioning – Adding the Dimmable Light Bulb and Dimmer to the Group

3.After the group is created, follow these steps to add nodes to the group “building 6.2”:

a. Before you proceed with these steps, ensure that all evaluation boards are powered ON.

b. Select Add Device.
A new window will pop up displaying all unprovisioned Mesh devices that are advertising. In this case, as all devices are powered, it will show all four devices we have programmed. Dimmable Light Bulbs are shown as Dimmable Light with their associated Bluetooth address.

c. Tap on one Dimmable Light device and then enter the name you want to give to this node. For this example, we will use name “Bulb 1”. Then select OK to start the “Provisioning” and “Configuration” process. Observe the status message “Provision Complete” after the process is complete. Do not take any action until you see this message. Once you see the message, the Dimmable Light device with the name “Bulb 1” is part of the Mesh network.

d. Repeat these steps for the other three devices for Use Case #1. In this example, we have used names “Bulb 2” and “Bulb 3” for the other two Dimmable Light devices and “Dimmer” for Dimmer Switch device. You can use the name of your choice.

Figure 69. Connecting to the Network

4.The Dimmer Switch node can control the Dimmable Light Bulbs directly without the need of the Cypress Android Helper app. The Dimmer Switch controls the LED on the three Dimmable Light Bulbs through the User Button on the Dimmer Switch evaluation board. The User Button actions and associated Mesh messages that are sent out from the Dimmer Switch are detailed below:

a. A short press and release of the User Button on the Dimmer Switch node will toggle the ON/OFF state of the LED on the Dimmable Light Bulb nodes.

b. A long press of User Button on the Dimmer Switch node sends a 12.5% level increase command every 500 milli-seconds. It takes 4 seconds for the level of the Dimmable Light Bulb Nodes to increase from 0% to 100%. The Dimmer Switch node will stop sending commands after 100% level setting is achieved.

c. After the Dimmer Switch has reached the minimum or maximum level setting (0% or 100%), releasing the User Button and repeating a long press will repeat the inverse level controls to the Dimmable Light Bulbs. For example, in Step 4.b above, the Dimmable Light Bulbs level setting were increased to 100%. After releasing the User Button and repeating the long press of the User Button, the level setting will decrease from 100% to 0% in 12.5% decrements every 500 milli-seconds.

5.The Cypress Android Helper app can also be used to control the Dimmable Light Bulbs. To access and control the nodes in the group using the Android Helper app, the phone must be connected to the network. If a node supports the Proxy feature, by default the phone will remain connected to this Proxy nodafter it completes provisioning. If the phone is connected to the network, a green bar is shown at the bottom of the Android app. A red bar in this location indicates that the phone is not connected to the network. If the Dimmer Switch is the last node that is provisioned, the phone will disconnect from the network after provisioning as the Dimmer Switch node does not support the Proxy feature. Therefore, before you can control these nodes, ensure that the status bar is green. If the status bar is red, follow these steps to connect to the network:

a. Select the Connect To Network, button on the bottom right hand side of the screen. A new screen will be prompted that will ask if you want to connect to the Mesh Network. Select OK.

b. Wait until status bar turns green.

Figure 70. Controlling the Dimmable Light Bulbs in The Group

6.Follow these steps to access the nodes in the group.

a. To control each node individually, select the individual node. This will bring up a screen where this node can be accessed.

b. Tap on the ON/OFF button to change state from Off to On and vice-versa. You can control the LED intensity by changing the Level slider position. Observe the LED state and intensity while you modify the settings in the Android app.

c. Once done, tap on the arrow on the top left of the screen to go back to the group.

d. To control the entire group, select the ON/OFF button on the group’s home screen. Observe that the LEDs on all Dimmable Light nodes will change according to your changes.