Designing a Custom Zigbee 3.0 Certifiable Product Using SampleApp#

Introduction#

The intention of this lab is to help developers create their own custom Zigbee 3.0 devices using Z-Stack. Topics that we will cover in this lab include:

  1. Choosing a certifiable Zigbee device type from the Zigbee device type specifications

  2. Gathering the required information about your chosen Zigbee device from the Zigbee documentation

  3. Modifying the sample applications provided in the SimpleLink SDK to suit the needs of your chosen Zigbee device

Z-Stack is a component of the SimpleLink CC13xx / CC26xx Software Development Kit and is a complete Zigbee 3.0 software solution.

Note: This lab is intended to be a starting point for development, it does not go into details about how to test and verify the final product.

Note

Technical support For any questions you may have, please refer to the TI Zigbee & Thread E2E Forum.

Prerequisites#

Background#

  • Familiarity with the Zigbee 3.0 specification

    • More information about the changes in Zigbee 3.0 compared to older specifications can be found in SWRA615

  • Basic CCS knowledge

  • Some basic familiarity with embedded programming

Software#

Zigbee Documentation#

  • Zigbee Cluster Library v7 Specification (ZCL spec) - Zigbee Document number 07-5123-07

  • Zigbee Lighting and Occupancy Device Specification (ZLO spec) - Zigbee Document number 15-0014-05

  • Zigbee Home Automation Public Application Profile (ZHA spec) - Zigbee Document number 05-3520-29

Note

Note Zigbee documentation can be obtained from the Connectivity Standards Alliance

Gathering information from Zigbee documentation#

Before we jump into the software, our first task is to determine which type of Zigbee device we wish to create. Then we must determine which clusters that device must support and which attributes those clusters must support.

Choosing a Zigbee device type#

There are currently two specifications we can refer to for choosing a Zigbee device type, the Zigbee Lighting and Occupancy Device Specification (ZLO spec) and the Zigbee Home Automation Public Application Profile (ZHA spec).

Go to the “Device Descriptions” sections of both documents, Section 5 in the ZLO spec and Section 5.7 in the ZHA spec. At first glance you will notice that there is some overlap between these two specifications, namely Device ID 0x0100 through 0x0107. If you are creating one of these Zigbee Lighting devices, refer to the information in the ZLO spec instead of the ZHA spec. The ZLO spec is the newest device specification document that has been released by the Connectivity Standards Alliance, so the information in this document is newer and supersedes anything regarding these devices types in the ZHA spec. For all other non-overlapping device types between these two documents, the current instructions from the Zigbee Alliance website are to follow the guidelines in each corresponding document for each device type.

So, let’s say we want to create a Door Lock as our Zigbee device. In Section 5.7 of the ZHA spec, we can see in Table 5.1 below that this device has Device ID 0x000A.

ZHA Spec: Table 5.1 Devices Specified in the HA Profile
../../../_images/ZHA_Table_5_1.png

Table 5.1#

Determining which clusters our device support#

In the same document that we chose our Zigbee device out of, we can navigate to the section that defines what clusters our device supports. In our case, we need go to Section 7.4.10 of the ZHA spec for Door Lock. From here we can determine which clusters our device supports under the subsection ‘Supported Clusters’.

Here are all the important points from the images below:

  • Mandatory and Optional Clusters

    • All Zigbee devices must implement their mandatory clusters to pass Zigbee device certification. Zigbee device manufacturers may choose to implement certain optional clusters for their own application needs.

    Note

    If you choose to implement an optional cluster, even though it is marked as optional, you must still pass certification for that cluster if you wish to include it with your device

  • Server Side and Client Side cluster implementation

    • Implementing the Server vs. the Client side of a cluster is very important because it determines which attributes you support.

  • Common Clusters for all Zigbee devices

    • All Zigbee devices support a common set of mandatory and optional clusters, listed below in table 7.1. We can see in section 7.4.10.1 below that it mentions “In addition to those specified in Table 7.1”

ZHA Spec: Section 7.4.10.1 Supported Clusters for Door Lock
../../../_images/ZHA_Section_7_4_10_1.png

Section 7.4.10.1#

ZHA Spec: Table 7.1 Clusters Common to All Devices
../../../_images/ZHA_Table_7_1.png

Table 7.1#

Now, using the information from the tables above, let’s make new table that shows what clusters our Door Lock device is going to support. Only the mandatory clusters are selected for this example.

SLA Table 1: Cluster table for Door Lock device

Cluster ID

Cluster Name

Client/Server Side

0x0000

Basic

Server

0x0003

Identify

Client + Server

0x0004

Groups

Server

0x0005

Scenes

Server

0x0101

Door Lock

Server

Determining which attributes our clusters support#

Now that we have a list of clusters, we can refer to the Zigbee Cluster Library v7 Specification (ZCL spec). The ZCL spec will tell us which attributes our selected clusters support. Each section of the ZCL spec will give us a cluster and tell us which attributes the Server Side and Client Side implementations of that cluster support.

As of the ZCL v6 spec, it is mandatory for every cluster to support the ClusterRevision attribute.

ZCL Spec: Table 2-1 Global attributes for every cluster
../../../_images/ZCL_Table_2-1.png

Table 2-1#

Let’s start with the Basic Cluster. From the table we made in the previous section, we must support the Basic Cluster Server. Table 3-7 in Section 3.2.2.2 of the ZCL spec tells us which attributes the Basic Cluster Server supports.

ZCL Spec: Table 3-7 Attributes supported by Basic Cluster Server
../../../_images/ZCL_Table_3-7_1.png

Table 3-7_1#

../../../_images/ZCL_Table_3-7_2.png

Table 3-7_2#

Next we can find the Identify Cluster, for which we must support both Client and Server. Table 3-28 in section 3.5.2.2 of the ZCL spec tells us which attributes the Identify Cluster Server supports. Section 3.5.2.1 of the ZCL spec tells us that the Identify Cluster Client does not support any cluster specific attributes.

ZCL Spec: Table 3-31 Attributes supported by Identify Cluster Server
../../../_images/ZCL_Table_3-31.png

Table 3-31#

Next is the Groups Cluster, for which we must support both Client and Server. Table 3-36 of section 3.6.2.2 of the ZCL spec tells us which attributes the Groups Cluster Server supports. The same can be said of Table 3-40 of section 3.7.2.2.1 for the Scenes Cluster and Table 7-8 of section 7.3.2.10 for the Door Lock Cluster, all for the Server side.

ZCL Spec: Table 3-36 Attributes supported by Groups Cluster Server
../../../_images/ZCL_Table_3-36.png

Table 3-31#

ZCL Spec: Table 3-40 Attributes supported by Scenes Cluster Server
../../../_images/ZCL_Table_3-40.png

Table 3-31#

ZCL Spec: Table 7-8 Attributes supported by Door Lock Cluster Server
../../../_images/ZCL_Table_7-8.png

Table 3-31#

Once again, a new table is created using the information from the tables above that shows us which attributes our Door Lock device is going to support. Only the madatory attributes are selected for this example.

SLA Table 2: Attribute table for Door Lock device

Attribute

Cluster

Data Type

Access

Default Value

ZCLVersion

Basic

uint8

Read

2

PowerSource

Basic

enum8

Read

0

ClusterRevision

Basic

uint16

Read

1

IdentifyTime

Identify

uint16

Read/Write

0

ClusterRevision

Identify

uint16

Read

1

NameSupport

Groups

map8

Read

0

ClusterRevision

Groups

uint16

Read

1

SceneCount

Scenes

uint8

Read

0

CurrentScene

Scenes

uint8

Read

0

CurrentGroup

Scenes

uint16

Read

0

SceneValid

Scenes

bool

Read

0

NameSupport

Scenes

map8

Read

0

ClusterRevision

Scenes

uint16

Read

1

LockState

Door Lock

enum8

Read/Reportable

0

LockType

Door Lock

enum8

Read

0

ActuatorEnabled

Door Lock

bool

Read

0

ClusterRevision

Door Lock

uint16

Read

1

Warning

Reportable Attributes: If any of the attributes you are supporting have an access type of Reportable, it is mandatory for your device to support ZCL reporting which means your device will need to include the compile flag BDB_REPORTING which enables ZCL report sending capabilities. We will revisit this again later on in the lab.

Modifying the SampleApp project#

It’s finally time to start modifying the software to suit our needs. We will be referencing the SampleApp project to create a custom certifiable application using the SysConfig Application Builder. You can learn more about this feature in the TI Z-Stack User’s Guide. You can find the project in the following location:

C:\ti\simplelink_cc13xx_cc26xx_sdk_<version>\examples\rtos\<LaunchPad variant>\zstack\zr_sampleapp

Importing the project into Code Composer Studio#

Now we are ready to import the project into Code Composer Studio (CCS). Open CCS and go to File > Import > C/C++ Project > CCS Project and then browse for the zr_sampleapp project path under Select search-directory:

Import our modified SampleApp into CCS
../../../_images/CCS_Project_Import.png

Project Import#

At this point it is a good idea to try building the project just to make sure all the file paths resolve correctly, this will verify that we have a good starting point for our incoming code modifications.

Using the SysConfig Application Builder#

The SysConfig Application Builder will automate several ZCL configurations. This consists of defining compile flags in ti_zstack_config.h along with including all attributes, server/client clusters, simple descriptors, callback definitions, and initialization code inside the zcl_config.c file. First, open the zr_sampleapp.syscfg > Z-Stack > Zigbee Application Endpoint menu and select Generic as the Zigbee Device Type. It is possible to change the Application Name to “Door Lock” or another suitable name of choice, however this lab will keep the default “Sample App” naming convention.

Zigbee Application Endpoint view in SysConfig
../../../_images/Zigbee_Application_Builder.png

Project Import#

Note

Although a Door Lock is provided as a pre-configured certifiable Zigbee Device Type, we will build one from scratch for the purposes of this lab.

The following list details what all is configured inside the Zigbee Application Builder

  1. Viewing Mandatory Clusters

  2. Adding Additional Clusters

  3. Choosing BDB Reporting and Advanced Settings

Viewing Mandatory Clusters#

We can select the Mandatory Clusters tab to see that only the Basic and Identify clusters are defined as the Server Clusters. This is the default requirement for a Generic Zigbee Device Type and no further changes are required towards these settings. Optional Attributes and Optional Commands Generated/Received can be added if necessary for the application. Groups is listed under Server Clusters from Recommended Optional Clusters and should be chosen accordingly.

Mandatory Clusters
../../../_images/Mandatory_Clusters.png

Project Import#

Adding Additional Clusters#

Inside the Additional Clusters tab is where we will add the clusters from SLA Table 1, excluding Basic and Identify for the server side as they are already covered by the Mandatory Clusters. For Server Clusters, select Scenes and DoorLock. Client Clusters need only add Identify.

Additional Clusters
../../../_images/Additional_Clusters.png

Project Import#

Doing this will prompt the Zigbee Application Builder to automatically fill the Mandatory Attributes tab with the attributes described in SLA Table 2. The Mandatory Commands Generated/Received are also populated. Optional Attributes and Optional Commands Generated/Received can also be added based on application needs.

Choosing BDB Reporting and Advanced Settings#

As SLA Table 2 identifies a reportable attribute which was added when configuring the Additional Clusters, the BDB Reporting tab becomes available. These values, alongside those of the Advanced Settings tab, can be chosen according to the developer’s requirements. More information can be obtained in the SysConfig section of the TI Z-Stack User’s Guide. For the purpose of this lab, however, the default values will be used.

BDB Reporting and Advanced Settings
../../../_images/BDB_Reporting_Advanced_Settings.png

Project Import#

After completing all configurations inside the SysConfig Zigbee Application Builder, we will build the project to generate the zcl_config.c/h file which will be located in the default/sysconfig folder. It is here that we can view the ZCL attribute variables/default values, attribute lists, command lists, callbacks, and simple descriptors that were created based on our previous selections. We also see that a zclConfigInit function is created to initialize this code, and is called by sampleApp_Init of sampleapp.c.

Warning

SysConfig output: Files found in the default/sysconfig folder must never be directly edited as they will be re-written each time the project is built. Changes can only be made by modifying the corresponding SysConfig module or copying files into the main project directory after de-selecting Include in build from the SysConfig Generated File View.

All of the ZCL source code files are included in the SampleApp project by default, but the functionality contained in each file is compiled out via compile flags. The table below shows which compile flags will be added to ti_zstack_config.h based on the clusters listed in SLA Table 1.

SLA Table 3: Compile Flag to Cluster correspondence

Cluster ID

Cluster Name

Compile Flags

0x0000

ZCL_CLUSTER_ID_GEN_BASIC

ZCL_BASIC

0x0001

ZCL_CLUSTER_ID_GEN_POWER_CFG

N/A

0x0002

ZCL_CLUSTER_ID_GEN_DEVICE_TEMP_CONFIG

N/A

0x0003

ZCL_CLUSTER_ID_GEN_IDENTIFY

ZCL_IDENTIFY

0x0004

ZCL_CLUSTER_ID_GEN_GROUPS

ZCL_GROUPS

0x0005

ZCL_CLUSTER_ID_GEN_SCENES

ZCL_SCENES

0x0006

ZCL_CLUSTER_ID_GEN_ON_OFF

ZCL_ON_OFF

0x0007

ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG

N/A

0x0008

ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL

ZCL_LEVEL_CTRL

0x0009

ZCL_CLUSTER_ID_GEN_ALARMS

ZCL_ALARMS

0x000A

ZCL_CLUSTER_ID_GEN_TIME

N/A

0x000B

ZCL_CLUSTER_ID_GEN_LOCATION

ZCL_LOCATION

0x000C

ZCL_CLUSTER_ID_GEN_ANALOG_INPUT_BASIC

N/A

0x000D

ZCL_CLUSTER_ID_GEN_ANALOG_OUTPUT_BASIC

N/A

0x000E

ZCL_CLUSTER_ID_GEN_ANALOG_VALUE_BASIC

N/A

0x000F

ZCL_CLUSTER_ID_GEN_BINARY_INPUT_BASIC

N/A

0x0010

ZCL_CLUSTER_ID_GEN_BINARY_OUTPUT_BASIC

N/A

0x0011

ZCL_CLUSTER_ID_GEN_BINARY_VALUE_BASIC

N/A

0x0012

ZCL_CLUSTER_ID_GEN_MULTISTATE_INPUT_BASIC

N/A

0x0013

ZCL_CLUSTER_ID_GEN_MULTISTATE_OUTPUT_BASIC

N/A

0x0014

ZCL_CLUSTER_ID_GEN_MULTISTATE_VALUE_BASIC

N/A

0x0015

ZCL_CLUSTER_ID_GEN_COMMISSIONING

N/A

0x0016

ZCL_CLUSTER_ID_GEN_PARTITION

N/A

0x0019

ZCL_CLUSTER_ID_OTA

OTA_CLIENT_INTEGRATED

0x001A

ZCL_CLUSTER_ID_GEN_POWER_PROFILE

N/A

0x001B

ZCL_CLUSTER_ID_GEN_APPLIANCE_CONTROL

N/A

0x0020

ZCL_CLUSTER_ID_GEN_POLL_CONTROL

N/A

0x0021

ZCL_CLUSTER_ID_GREEN_POWER

N/A

0x0022

ZCL_CLUSTER_ID_MOBILE_DEVICE_CONFIGURATION

N/A

0x0023

ZCL_CLUSTER_ID_NEIGHBOR_CLEANING

N/A

0x0024

ZCL_CLUSTER_ID_NEAREST_GATEWAY

N/A

0x0100

ZCL_CLUSTER_ID_CLOSURES_SHADE_CONFIG

N/A

0x0101

ZCL_CLUSTER_ID_CLOSURES_DOOR_LOCK

ZCL_DOORLOCK

0x0102

ZCL_CLUSTER_ID_CLOSURES_WINDOW_COVERING

ZCL_WINDOWCOVERING

0x0200

ZCL_CLUSTER_ID_HVAC_PUMP_CONFIG_CONTROL

ZCL_HVAC_CLUSTER

0x0201

ZCL_CLUSTER_ID_HVAC_THERMOSTAT

ZCL_HVAC_CLUSTER

0x0202

ZCL_CLUSTER_ID_HVAC_FAN_CONTROL

ZCL_HVAC_CLUSTER

0x0203

ZCL_CLUSTER_ID_HVAC_DIHUMIDIFICATION_CONTROL

ZCL_HVAC_CLUSTER

0x0204

ZCL_CLUSTER_ID_HVAC_USER_INTERFACE_CONFIG

ZCL_HVAC_CLUSTER

0x0300

ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL

ZCL_LIGHT_LINK_ENHANCE

0x0301

ZCL_CLUSTER_ID_LIGHTING_BALLAST_CONFIG

ZCL_LIGHT_LINK_ENHANCE

0x0400

ZCL_CLUSTER_ID_MS_ILLUMINANCE_MEASUREMENT

N/A

0x0401

ZCL_CLUSTER_ID_MS_ILLUMINANCE_LEVEL_SENSING_CONFIG

N/A

0x0402

ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT

N/A

0x0403

ZCL_CLUSTER_ID_MS_PRESSURE_MEASUREMENT

N/A

0x0404

ZCL_CLUSTER_ID_MS_FLOW_MEASUREMENT

N/A

0x0405

ZCL_CLUSTER_ID_MS_RELATIVE_HUMIDITY

N/A

0x0406

ZCL_CLUSTER_ID_MS_OCCUPANCY_SENSING

N/A

0x0500

ZCL_CLUSTER_ID_SS_IAS_ZONE

ZCL_ZONE

0x0501

ZCL_CLUSTER_ID_SS_IAS_ACE

ZCL_ACE

0x0502

ZCL_CLUSTER_ID_SS_IAS_WD

ZCL_WD

0x0600

ZCL_CLUSTER_ID_PI_GENERIC_TUNNEL

N/A

0x0601

ZCL_CLUSTER_ID_PI_BACNET_PROTOCOL_TUNNEL

N/A

0x0602

ZCL_CLUSTER_ID_PI_ANALOG_INPUT_BACNET_REG

N/A

0x0603

ZCL_CLUSTER_ID_PI_ANALOG_INPUT_BACNET_EXT

N/A

0x0604

ZCL_CLUSTER_ID_PI_ANALOG_OUTPUT_BACNET_REG

N/A

0x0605

ZCL_CLUSTER_ID_PI_ANALOG_OUTPUT_BACNET_EXT

N/A

0x0606

ZCL_CLUSTER_ID_PI_ANALOG_VALUE_BACNET_REG

N/A

0x0607

ZCL_CLUSTER_ID_PI_ANALOG_VALUE_BACNET_EXT

N/A

0x0608

ZCL_CLUSTER_ID_PI_BINARY_INPUT_BACNET_REG

N/A

0x0609

ZCL_CLUSTER_ID_PI_BINARY_INPUT_BACNET_EXT

N/A

0x060A

ZCL_CLUSTER_ID_PI_BINARY_OUTPUT_BACNET_REG

N/A

0x060B

ZCL_CLUSTER_ID_PI_BINARY_OUTPUT_BACNET_EXT

N/A

0x060C

ZCL_CLUSTER_ID_PI_BINARY_VALUE_BACNET_REG

N/A

0x060D

ZCL_CLUSTER_ID_PI_BINARY_VALUE_BACNET_EXT

N/A

0x060E

ZCL_CLUSTER_ID_PI_MULTISTATE_INPUT_BACNET_REG

N/A

0x060F

ZCL_CLUSTER_ID_PI_MULTISTATE_INPUT_BACNET_EXT

N/A

0x0610

ZCL_CLUSTER_ID_PI_MULTISTATE_OUTPUT_BACNET_REG

N/A

0x0611

ZCL_CLUSTER_ID_PI_MULTISTATE_OUTPUT_BACNET_EXT

N/A

0x0612

ZCL_CLUSTER_ID_PI_MULTISTATE_VALUE_BACNET_REG

N/A

0x0613

ZCL_CLUSTER_ID_PI_MULTISTATE_VALUE_BACNET_EXT

N/A

0x0614

ZCL_CLUSTER_ID_PI_11073_PROTOCOL_TUNNEL

N/A

0x0615

ZCL_CLUSTER_ID_PI_ISO7818_PROTOCOL_TUNNEL

N/A

0x0617

ZCL_CLUSTER_ID_PI_RETAIL_TUNNEL

N/A

0x0700

ZCL_CLUSTER_ID_SE_PRICE

ZCL_SE_PRICE_SERVER, ZCL_SE_PRICE_CLIENT

0x0701

ZCL_CLUSTER_ID_SE_DRLC

ZCL_SE_DRLC_SERVER, ZCL_SE_DRLC_CLIENT

0x0702

ZCL_CLUSTER_ID_SE_METERING

ZCL_SE_METERING_SERVER, ZCL_SE_METERING_CLIENT

0x0703

ZCL_CLUSTER_ID_SE_MESSAGING

ZCL_SE_MESSAGING_SERVER, ZCL_SE_MESSAGING_CLIENT

0x0704

ZCL_CLUSTER_ID_SE_TUNNELING

ZCL_SE_TUNNELING_SERVER, ZCL_SE_TUNNELING_CLIENT

0x0705

ZCL_CLUSTER_ID_SE_PREPAYMENT

ZCL_SE_PREPAYMENT_SERVER, ZCL_SE_PREPAYMENT_CLIENT

0x0706

ZCL_CLUSTER_ID_SE_ENERGY_MGMT

ZCL_SE_ENERGY_MGMT_SERVER, ZCL_SE_ENERGY_MGMT_CLIENT

0x0707

ZCL_CLUSTER_ID_SE_CALENDAR

ZCL_SE_CALENDAR_SERVER, ZCL_SE_CALENDAR_CLIENT

0x0708

ZCL_CLUSTER_ID_SE_DEVICE_MGMT

ZCL_SE_DEVICE_MGMT_SERVER, ZCL_SE_DEVICE_MGMT_CLIENT

0x0709

ZCL_CLUSTER_ID_SE_EVENTS

ZCL_SE_EVENTS_SERVER, ZCL_SE_EVENTS_CLIENT

0x070A

ZCL_CLUSTER_ID_SE_MDU_PAIRING

ZCL_SE_MDU_PAIRING_SERVER, ZCL_SE_MDU_PAIRING_CLIENT

0x0800

ZCL_CLUSTER_ID_SE_KEY_ESTABLISHMENT

ZCL_KEY_ESTABLISH

0x0900

ZCL_CLUSTER_ID_TELECOMMUNICATIONS_INFORMATION

N/A

0x0904

ZCL_CLUSTER_ID_TELECOMMUNICATIONS_CHATTING

N/A

0x0905

ZCL_CLUSTER_ID_TELECOMMUNICATIONS_VOICE_OVER_ZIGBEE

N/A

0x0B00

ZCL_CLUSTER_ID_HA_APPLIANCE_IDENTIFICATION

ZCL_APPLIANCE_IDENTIFICATION

0x0B01

ZCL_CLUSTER_ID_HA_METER_IDENTIFICATION

ZCL_METER_IDENTIFICATION

0x0B02

ZCL_CLUSTER_ID_HA_APPLIANCE_EVENTS_ALERTS

ZCL_APPLIANCE_EVENTS_ALERTS

0x0B03

ZCL_CLUSTER_ID_HA_APPLIANCE_STATISTICS

ZCL_APPLIANCE_STATISTICS

0x0B04

ZCL_CLUSTER_ID_HA_ELECTRICAL_MEASUREMENT

ZCL_ELECTRICAL_MEASUREMENT

0x0B05

ZCL_CLUSTER_ID_HA_DIAGNOSTIC

ZCL_DIAGNOSTIC

0x1000

ZCL_CLUSTER_ID_TOUCHLINK

N/A

In addition to the compile flags in the table above, it is also considered whether any attributes have an access type of ‘Reportable’, which is information that we recorded in SLA Table 2. If there is an attribute that is ‘Reportable’, it is also included as the compile flag BDB_REPORTING in the ti_zstack_config.h file.

For our Door Lock device, the compile flags ZCL_BASIC, ZCL_IDENTIFY, ZCL_GROUPS, ZCL_SCENES, ZCL_DOORLOCK and BDB_REPORTING will be included in the SysConfig output once the corresponding Clusters and Attributes are added. They can be viewed in the default/syscfg/ti_zstack_config.h after building the project.

ZCL Compile Flags generated by SysConfig
ti_zstack_config.h#
/* Cluster Flags */
#define ZCL_SYSCONFIG
#define ZCL_READ
#define ZCL_WRITE
#define ZCL_DISCOVER
#define ZCL_BASIC
#define ZCL_IDENTIFY
#define ZCL_GROUPS
#define ZCL_SCENES
#define ZCL_DOORLOCK
#define BDB_REPORTING

Making code changes to suit our selected Zigbee device#

As the SysConfig Zigbee Application Builder has automated setup of the ZCL layer inside zcl_config.h/c, all that remains is to copy the command callback functions, attribute variables, and default values into sampleapp.c and remove the WEAK tags so that they are correctly re-defined outside of the generated SysConfig files.

ZCL command callback functions are where your hardware-specific actions are performed in relation to the state of your cluster attributes. For instance, if you receive a Zigbee command from another device that changes the state of your Door Lock Cluster “LockState” attribute, you can receive a callback to your application saying that something happened, and at this point you would update your global attribute variable with the value passed into the callback function as a parameter and perform your hardware-specific action such as toggling a GPIO pin to reflect the new state of your attribute.

To receive these callback functions in your application, you must register a list of function pointers with each corresponding ZCL module. By default, zcl_config.c already does this with zclConfigInit:

ZCL command callback registration
zcl_config.c#
static void zclConfigInit( void )
{
  ...

  zclGeneral_RegisterCmdCallbacks( SAMPLEAPP_ENDPOINT, &sampleApp_zclGeneralCmdCallbacks );
  zclClosures_RegisterDoorLockCmdCallbacks( SAMPLEAPP_ENDPOINT, &sampleApp_zclClosuresCmdCallbacks );
  
  ...
}

The second parameter we pass into this function is the list of function pointers that we wish to register with the ZCL module. For every function present on this list we will receive a callback in our application when the corresponding action has been triggered, and we can set any callback we do not wish to receive to NULL. To know which callback functions are available, you must look into the corresponding zcl<module>_AppCallbacks_t struct in the ZCL header files. Since the Basic, Identify, Groups, and Scenes clusters are all part of the ZCL General group (i.e. check Chapter 3 of the ZCL spec), all of their callback function descriptions are in the struct zclGeneral_AppCallbacks_t in zcl_general.h. For the Door Lock cluster, this is part of the Closures group, so it is in the struct zclClosures_DoorLockAppCallbacks_t in zcl_closures.h. Each function in these structs has a typedef associated with it so you can know how to implement the function prototype and definition in your application. For instance, for the Door Lock callback, it has the type zclClosures_DoorLock_t in the struct zclClosures_DoorLockAppCallbacks_t, and we can see the typedef definition is as below:

typedef ZStatus_t (*zclClosures_DoorLock_t) ( zclIncoming_t *pInMsg, zclDoorLock_t *pInCmd );

And in zcl_config.c the function is already defined as such:

WEAK ZStatus_t sampleApp_DoorLockCB( zclIncoming_t *pInMsg, zclDoorLock_t *pInCmd ) { return ((ZStatus_t) 0); }

However, this is an empty function which does not accomplish anything. To re-define it for application use, it must be copied into sampleapp.c and remove the WEAK tag. This directs the compiler to use the callback function declared inside this file instead.

ZCL command callback use
sampleapp.c#
// Declaring the function at the top of the file
ZStatus_t sampleApp_DoorLockCB( zclIncoming_t *pInMsg, zclDoorLock_t *pInCmd );
...
// Implementing the function further in the file
ZStatus_t sampleApp_DoorLockCB( zclIncoming_t *pInMsg, zclDoorLock_t *pInCmd )
{
// Perform action based on application needs
return 0;
}

The same can be done for ZCL attribute variables, like sampleApp_DoorLock_LockState.

As mentioned before, the ZCL command callback functions are where you, the developer, must implement your hardware-specific functionality in your application code based on the high-level intended action of each ZCL command. This is the part of the code where, aside from provided HAL drivers, there is no specific framework for how you should implement your actions since it is highly dependent on your custom hardware design. One thing you must do, however, is update the state of your global attribute(s) in these callback functions (if applicable).

As an example, in the Door Lock cluster “DoorLock” Callback, you would do at least 2 things:

  1. Update the state of your global “LockState” attribute based on the function parameter of the callback function.

  2. Perform a hardware-specific action that actually changes the state of your hardware, such as altering the door lock mechanism.