Green Power Application Overview

Green Power Device

A Green Power Device (GPD) is a special type of Zigbee device different from the three logical devices defined in Zigbee PRO: Coordinator, Router or End Device. These devices are designed for applications where the end product has a very strict energy budget, such as an energy-harvesting device or batteryless devices. GPDs follow their own Zigbee Green Power specification which defines the possible capabilities of a given GPD implementation, such as security level, commissioning procedures and supported commands per device definition.

As GPDs are the most restricted device in terms of functionality, these devices are not part of the Zigbee network unless they are commissioned to a Green Power Sink (GPS) device directly or through a Green Power Proxy (GPP). If the device to which a GPD is commissioned to is not present, then the GPD must be recommissioned, as it does not have a means to keep communication with any other device.

Once the GPD is commissioned it can send Green Power Data Frames (GPDF) which are converted by the GPP into Green Power Notifications (ZCL frames) that can travel through the Zigbee network until it reaches its GPS destination to be processed by the application. For further details on GPDs and their interactions with the network, please refer to Green Power.

General Application Architecture

This section describes how a Green Power Device application task is structured in more detail.

Green Power Device Configuration

gpd_config.h provides configuration definitions for parameters like device ID, security level and security keys. These are used at build time and determine the behavior of the device at runtime. Thus, to change the Green Power Device behavior, it is necessary to modify the definitions in ti_zstack_config.h. Descriptions of these values are listed below.

Green Power Device definitions
Name Description Values
DEVICE_ID (uint8) Green Power Device ID which indicates the device application functionality.
0x00 - 0xFF, refer to GPD spec
EXT_OPT_KEY_TYPE Specifies the type of key which GPDFs are secured with.
0b000 KEY_TYPE_NO_KEY
0b001 KEY_TYPE_ZIGBEE_NWK_KEY
0b010 KEY_TYPE_GPD_GROUP_KEY
0b011 KEY_TYPE_NWK_KEY_DERIVED_GPD_GROUP_KEY
0b100 KEY_TYPE_OUT_BOX_GPD_KEY
0b111 KEY_TYPE_DERIVED_INDIVIDUAL_GPD_KEY
GPD_APP_ID Unique identifier of the GPD, either the 4-byte SrcID or the IEEE Addr.
0b00 GPD_APP_TYPE_SRC_ID
0b10 GPD_APP_TYPE_IEEE_ID
GPDF_FRAME_DUPLICATES (uint8) Application-specific. Number of GPDF retries per packet.
0x00 - 0xFF (recommended to be low, more retries = more power consumption)
GPD_CHANNEL IEEE channel, 11 - 26 (in Hex).
0x0B - 0x1A
GP_SECURITY_KEY The 128-bit security key used to encrypt Green Power Data Frames.
8 bytes from all 0x00 to all 0xFF
GP_SECURITY_LEVEL Defines the security level for GPDF payload.
0b00 GP_SECURITY_LVL_NO_SEC
0b01 Reserved
0b10 GP_SECURITY_LVL_4FC_4MIC
0b11 GP_SECURITY_LVL_4FC_4MIC_ENCRYPT
AUTO_COMMISSIONING Defines whether or not the device will start commissioning procedure using application GPDF. This is for devices with limited resources not capable of sending commissioning frames.
TRUE/FALSE
RX_AFTER_TX RxOnCapability commissioning option. Defines whether or not GPD will turn RX on after TXing a frame, i.e. whether or not GPD is expecting a response.
TRUE/FALSE
SEQUENCE_NUMBER_CAP Defines if GPD will use incremental sequence numbers or random sequence numbers.
TRUE/FALSE
BATTERYLESS_DEVICE If defined, the GPD application is configured to operate in batteryless mode (if supported). For example, when gpd_sw is operating in batteryless mode, on power up it will immediately send an on, off, or toggle command (based on the combination of keys pressed).
Defined or not

An example of creating a GPD switch is given below (found in ti_zstack_config.h of the gpd_switch project).

#ifndef GPD_CHANNEL
#define GPD_CHANNEL            11
#endif

#ifndef DEVICE_ID
#define DEVICE_ID              0x02
#endif

#ifndef GPD_APP_ID
#define GPD_APP_ID             GPD_APP_TYPE_SRC_ID
#endif

#if ( GPD_APP_ID == GPD_APP_TYPE_SRC_ID )
#define GPD_ID                 0x11223344
#elif ( GPD_APP_ID == GPD_APP_TYPE_IEEE_ID )
#define GPD_ID                 ApiMac_extAddr
#endif

#ifndef GP_SECURITY_LEVEL
#define GP_SECURITY_LEVEL      GP_SECURITY_LVL_NO_SEC
#endif

#ifndef EXT_OPT_KEY_TYPE
#define EXT_OPT_KEY_TYPE       KEY_TYPE_OUT_BOX_GPD_KEY
#endif

#ifndef GP_SECURITY_KEY
#define GP_SECURITY_KEY        {0xCF,0xCE,0xCD,0xCC,0xCB,0xCA,0xC9,0xC8,0xC7,0xC6,0xC5,0xC4,0xC3,0xC2,0xC1,0xC0}
#endif

#ifndef GPDF_FRAME_DUPLICATES
#define GPDF_FRAME_DUPLICATES  3
#endif

#ifndef AUTO_COMMISSIONING
#define AUTO_COMMISSIONING     TRUE
#endif

#ifndef RX_AFTER_TX
#define RX_AFTER_TX            FALSE
#endif

#ifndef SEQUENCE_NUMBER_CAP
#define SEQUENCE_NUMBER_CAP    FALSE
#endif

Non Volatile Memory

gpd_memory.c provides an interface for Non Volatile (NV) memory required for attribute persistence in some GPD configurations. For example the persistence of sequence number when SEQUENCE_NUMBER_CAP is required. Use gp_nv_item_init() to create a new NV item, then gp_nv_read() to get the NV value and gp_nv_write() to update the NV value when necessary.

Callbacks

The application code also likely includes various callbacks from the protocol stack layer and RTOS modules. To ensure thread safety, processing should be minimized in the actual callback, and the bulk of the processing should be done in the application context.

static uint16 gpdSampleSw_process_loop( void )
{
    /* Forever loop */
    for(;;)
    {
        if(events & SAMPLEAPP_KEY_EVT)
        {
            // Process Key Presses
            gpdSampleSw_processKey(keys);
            keys = 0;
            events &= ~SAMPLEAPP_KEY_EVT;
        }

        ApiMac_processIncoming();
    }
}

Send Green Power Data Frames

An API to send Green Power Data Frames (GPDF) is provided in gpd.c. The generic function GreenPowerDataFrameSend() sends a frame formated for the Green Power Device configuration automatically by providing a gpdfReq_t struct, the desired channel and a flag to enable frame security.

Additionally GreenPowerCommissioningSend() and GreenPowerAttributeReportingSend() functions use GreenPowerDataFrameSend() to generate the corresponding commands.

Setting Up the Network with GPD and GPS

To set up a network with a Green Power Device (GPD) and a Green Power Sink (GPS), you will need 2-3 devices:

  1. Green Power Device (gpd_switch or gpd_temperaturesensor)
  2. Green Power Sink (zc/zr_light_sink or zc/zr_thermostat_sink)
  3. Optional: Green Power Proxy (any other Zigbee 3.0 routing device, e.g. zc/zr_genericapp)

Select Network Channel

First, determine which channel you would like to use for your test. On the Green Power Sink (and Green Power Proxy, if applicable), configure the channel mask accordingly (see Configuring Channel). Select the same channel for the Green Power Device (see Radio Configuration).

Create and Open the Network on the GPS

Next, create a network with your coordinator. For example, use zc_light_sink to create a network, following the instructions in the Commissioning the Device Into the Network section of this readme:

Join the GPP Device

If you would prefer a Green Power Proxy (GPP) to route GP Data Frames, it must be joined to the network formed by the coordinator. For example, we can use zr_genericapp as a GPP by simply joining it into the network, following the instructions Example Usage section of this readme:

  • Generic App Router Readme

    Note

    This step is entirely optional as the GPD can be directly commissioned to the GPS coordinator

Enable Commissioning on the GPS

Next, enable GPS Commissioning on the zc_light_sink by following the instructions in the Interfacing with the GP On/Off Switch Example App section of this readme:

Commission the GPD into the Network

Lastly, commission a GPD like the gpd_switch into the network by following the instructions in the Interfacing with the Light Sink Example App section of this readme:

Example Ubiqua Capture of Green Power Traffic

Here is an annotated Ubiqua capture of the expected behavior following the instructions above:

../_images/green-power-network-example.png

Adding Green Power Proxy Capabilities to Routing Sample Applications

As required for Zigbee 3.0, routing device sample applications must implement the proxy functionality (Green Power Proxy Basic, or GPPB). Although this functionality is enabled by default, for testing purposes it may be disabled by defining DISABLE_GREENPOWER_BASIC_PROXY.

This section will detail the necessary application code that is required for the GPPB. Note that necessary code to implement the GPPB is included in all routing sample applications (those prepended with zc_ or zr_).

  1. Include the gp_common header file, like in zcl_samplelight.c:

#include "gp_common.h"

  1. Add the three events for Green Power application events. Choose event bitmasks that aren’t already used for other events. Look at zcl_samplelight.h for reference.
// Green Power Events
#define SAMPLEAPP_PROCESS_GP_DATA_SEND_EVT              0x0100
#define SAMPLEAPP_PROCESS_GP_EXPIRE_DUPLICATE_EVT       0x0200
#define SAMPLEAPP_PROCESS_GP_TEMP_MASTER_EVT            0x0400

3. In the ZCL initialization function initialize the Green Power EndPoint and Green Power application events, like in zclSampleLight_Init().

gp_endpointInit(appServiceTaskId);
app_Green_Power_Init(appServiceTaskId, &appServiceTaskEvents, appSemHandle,
                     SAMPLEAPP_PROCESS_GP_DATA_SEND_EVT,
                     SAMPLEAPP_PROCESS_GP_EXPIRE_DUPLICATE_EVT,
                     SAMPLEAPP_PROCESS_GP_TEMP_MASTER_EVT);

4. Add the handlers for application events in the application process loop, like in zclSampleLight_process_loop(). All the required processing that the spec mandates is done by these handlers; any other processing specific to the application implementation is out of the specification scope.

static void zclSampleLight_process_loop(void)
{
  // Forever loop
  for(;;)
  {
    zstackmsg_genericReq_t *pMsg = NULL;

    // Wait for response message
    if(Semaphore_pend(appSemHandle, BIOS_WAIT_FOREVER ))
    {
    .
    .
    .
    if(appServiceTaskEvents & SAMPLEAPP_PROCESS_GP_DATA_SEND_EVT)
    {
      if(zgGP_ProxyCommissioningMode == TRUE)
      {
        zcl_gpSendCommissioningNotification();
      }
      else
      {
        zcl_gpSendNotification();
      }
      appServiceTaskEvents &= ~SAMPLEAPP_PROCESS_GP_DATA_SEND_EVT;
    }

    if(appServiceTaskEvents & SAMPLEAPP_PROCESS_GP_EXPIRE_DUPLICATE_EVT)
    {
      gp_expireDuplicateFiltering();
      appServiceTaskEvents &= ~SAMPLEAPP_PROCESS_GP_EXPIRE_DUPLICATE_EVT;
    }

    if(appServiceTaskEvents & SAMPLEAPP_PROCESS_GP_TEMP_MASTER_EVT)
    {
      gp_returnOperationalChannel();
      appServiceTaskEvents &= ~SAMPLEAPP_PROCESS_GP_TEMP_MASTER_EVT;
    }
    .
    .
    .

5. Add the handlers to process messages from the stack, like in zclSampleLight_processZStackMsgs(). All the required processing that the spec mandates is done by this handlers, any other processing specific to the application implementation is out of the specification scope.

static void zclSampleLight_processZStackMsgs(zstackmsg_genericReq_t *pMsg)
{
  switch(pMsg->hdr.event)
  {
  .
  .
  .
    case zstackmsg_CmdIDs_GP_DATA_IND:
    {
      zstackmsg_gpDataInd_t *pInd;
      pInd = (zstackmsg_gpDataInd_t*)pMsg;
      gp_processDataIndMsg( &(pInd->Req) );
    }
    break;

    case zstackmsg_CmdIDs_GP_SECURITY_REQ:
    {
      zstackmsg_gpSecReq_t *pInd;
      pInd = (zstackmsg_gpSecReq_t*)pMsg;
      gp_processSecRecMsg( &(pInd->Req) );
    }
    break;

    case zstackmsg_CmdIDs_GP_CHECK_ANNCE:
    {
      zstackmsg_gpCheckAnnounce_t *pInd;
      pInd = (zstackmsg_gpCheckAnnounce_t*)pMsg;
      gp_processCheckAnnceMsg( &(pInd->Req) );
    }
  .
  .
  .

Adding Green Power Sink Capabilities to Routing Sample Applications

This section provides guidance on how to add sink functionality to a coordinator or router sample application, using zc/zr_light as an example.

Basic Steps

In the SimpleLink CC13x2 / 26x2 SDK, sink examples are provided for the corresponding GPD examples. For example, there are zc/zr_light_sink and zc/zr_thermostat_sink, which respectively correspond to gpd_switch and gpd_temperaturesensor. Default application functionality is provided for the sinks to act upon the GPDFs sent by commissioned GPDs. For this reason, it is a simple task to enable the default sink functionality on zc/zr_light and zc/zr_thermostat:

  1. Add these files to <project>/Common/gp:
    • gp_bit_fields.c/h
    • gp_sink_table.c
    • gp_sink.c/h
  2. Add this to predefined symbols:
    • ENABLE_GREENPOWER_COMBO_BASIC
      • To access predefined symbols in CCS: (right-click project->:code:Project Properties->:code:Build->:code:ARM Compiler->:code:Predefined Symbols)
      • To access predifned symbols in IAR: (right-click project->:code:Options->:code:C/C++ Compiler->:code:Preprocessor->:code:Defined symbols)

Detailed Steps of Adding Sink Functionality

Here are detailed instructions on adding sink functionality. This will serve as a guide on how other sample applications may also be modified to support their respective GPD. The zc/zr_light sample application will be used for this purpose.

  1. Define ENABLE_GREENPOWER_COMBO_BASIC compilation flag on the project options to enable the sink related functionality.

2. Declare the sink application callbacks struct (GpSink_AppCallbacks_t) like in zcl_samplelight.c. The pointers defined in this structure are the callbacks that will process the Green Power application commands sent by the Green Power Devices. This example only defines pointers for a Sample Light application; every thing else is declared as null. Adjust this structure according to the specific application requirements.

GpSink_AppCallbacks_t zclSampleLight_GpSink_AppCallbacks =
{
#ifdef ZCL_IDENTIFY
    zclSampleLight_GPSink_Identify,     //IdentifyCmd;
#endif
#ifdef ZCL_SCENES
    NULL,                               //RecallSceneCmd;
    NULL,                               //StoreSceneCmd;
#endif
#ifdef ZCL_ON_OFF
    zclSampleLight_GPSink_Off,          //OffCmd;
    zclSampleLight_GPSink_On,           //OnCmd;
    zclSampleLight_GPSink_Toggle,       //ToggleCmd;
#endif
#ifdef ZCL_LEVEL_CTRL
    NULL,                               //LevelControlStopCmd;
    NULL,                               //MoveUpCmd;
    NULL,                               //MoveDownCmd;
    NULL,                               //StepUpCmd;
    NULL,                               //StepDownCmd;
    NULL,                               //MoveUpWithOnOffCmd;
    NULL,                               //MoveDownWithOnOffCmd;
    NULL,                               //StepUpWithOnOffCmd;
    NULL,                               //StepDownWithOnOffCmd;
#endif
    NULL,                               //MoveHueStopCmd;
    NULL,                               //MoveHueUpCmd;
    NULL,                               //MoveHueDownCmd;
    NULL,                               //StepHueUpCmd;
    NULL,                               //StepHueDownCmd;
    NULL,                               //MoveSaturationStopCmd;
    NULL,                               //MoveSaturationUpCmd;
    NULL,                               //MoveSaturationDownCmd;
    NULL,                               //StepSaturationUpCmd;
    NULL,                               //StepSaturationDownCmd;
    NULL,                               //MoveColorCmd;
    NULL,                               //StepColorCmd;
#ifdef ZCL_DOORLOCK
    NULL,                               //LockDoorCmd;
    NULL,                               //UnlockDoorCmd;
#endif
    NULL,                               //AttributeReportingCmd;
    NULL,                               //MfrSpecificReportingCmd;
    NULL,                               //MultiClusterReportingCmd;
    NULL,                               //MfrSpecificMultiReportingCmd;
    NULL,                               //RequestAttributesCmd;
    NULL,                               //ReadAttributeRspCmd;
    NULL,                               //zclTunnelingCmd;
};
  1. Register the sink application callbacks using zclGp_RegisterCBForGPDCommand(&zclSampleLight_GpSink_AppCallbacks);, as in zclSampleLight_Init().
static void zclSampleLight_Init( void )
{

    // ...

#if defined (ENABLE_GREENPOWER_COMBO_BASIC)
    zclGp_RegisterCBForGPDCommand(&zclSampleLight_GpSink_AppCallbacks);
#endif

    // ...

}
  1. Declare all the functions required as application callbacks by the sink. Look at zcl_samplelight.c for reference.
/*********************************************************************
 * @fn      zclSampleLight_GPSink_Identify
 *
 * @brief   Callback to process Identify command from a GPD
 *
 * @param   zclGpNotification
 *
 * @return  none
 */
static void zclSampleLight_GPSink_Identify(zclGpNotification_t *zclGpNotification)
{
  afAddrType_t  dstAddr;

  dstAddr.endPoint = SAMPLELIGHT_ENDPOINT;
  dstAddr.panId = 0;
  dstAddr.addrMode = afAddr16Bit;
  dstAddr.addr.shortAddr = _NIB.nwkDevAddress;

  //Identify is a payloadless command which triggers a 60 seconds identify in
  /// the device (doc 14-0563-16 GP spec Table 49)
  zclGeneral_SendIdentify(SAMPLELIGHT_ENDPOINT,&dstAddr,60,TRUE, 1);
}

/*********************************************************************
 * @fn      zclSampleLight_GPSink_Off
 *
 * @brief   Callback to process Off command from a GPD
 *
 * @param   zclGpNotification
 *
 * @return  none
 */
static void zclSampleLight_GPSink_Off(zclGpNotification_t *zclGpNotification)
{
  zclSampleLight_OnOffCB(COMMAND_OFF);
}

/*********************************************************************
 * @fn      zclSampleLight_GPSink_On
 *
 * @brief   Callback to process On command from a GPD
 *
 * @param   zclGpNotification
 *
 * @return  none
 */
static void zclSampleLight_GPSink_On(zclGpNotification_t *zclGpNotification)
{
  zclSampleLight_OnOffCB(COMMAND_ON);
}

/*********************************************************************
 * @fn      zclSampleLight_GPSink_Toggle
 *
 * @brief   Callback to process Toggle command from a GPD
 *
 * @param   zclGpNotification
 *
 * @return  none
 */
static void zclSampleLight_GPSink_Toggle(zclGpNotification_t *zclGpNotification)
{
  zclSampleLight_OnOffCB(COMMAND_TOGGLE);
}