Top Banner
© 2015 sivann inc. All Rights Reserved © 2015 sivann inc. All Rights Reserved Pursue of Simplicity [email protected] ZigBee ZCL Reporting Configuration Example: TI Z-Stack Home 1.2.1/1.2.2 SampleLight
42

Implementation of the ZigBee ZCL Reporting Configuration Features

Jul 18, 2015

Download

Software

simenli
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Implementation of the ZigBee ZCL Reporting Configuration Features

© 2015 sivann inc. All Rights Reserved© 2015 sivann inc. All Rights Reserved

Pursue of Simplicity

[email protected]

ZigBee ZCL Reporting ConfigurationExample: TI Z-Stack Home 1.2.1/1.2.2 SampleLight

Page 2: Implementation of the ZigBee ZCL Reporting Configuration Features

2

“The ZCL acts as a repository for cluster functionality that

is developed by ZigBee. A developer constructing a new

profile should incorporate relevant ZCL cluster

functionality into the new profile.” [1]

ZCL foundation provides “general commands” for

manipulating attributes and other general tasks that are

not specific to an individual cluster.

Introduction

Page 3: Implementation of the ZigBee ZCL Reporting Configuration Features

3

ZCL foundation general commands are provided with TI’s

Z-Stack ZCL APIs.

◦ Commands Read/Write (0x00 – 0x05) are handled in ZCL Foundation

Layer, and TI leaves the features of attribute reporting (0x06 – 0x0A)

for the developers to implement on application-level by their needs.

ZCL Foundation – General Commands

Cmd Id Description

0x00 Read attributes

0x01 Read attributes response

0x02 Write attributes

0x03 Write attributes undivided

0x04 Write attributes response

0x05 Write attributes no response

0x06 Configure reporting

0x07 Configure reporting response

0x08 Read reporting configuration

0x09 Read reporting configuration response

0x0A Report attributes

Page 4: Implementation of the ZigBee ZCL Reporting Configuration Features

4

Implement these features within the incoming message handlers

zclSampleLight_ProcessInConfigReportCmd(), .etc.

ZCL_REPORT Feature in zcl_samplelight.c

static void zclSampleLight_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg ){switch ( pInMsg->zclHdr.commandID ){

...

#ifdef ZCL_REPORT

// Attribute Reporting implementation should be added here

case ZCL_CMD_CONFIG_REPORT:// zclSampleLight_ProcessInConfigReportCmd( pInMsg );

break;case ZCL_CMD_CONFIG_REPORT_RSP:// zclSampleLight_ProcessInConfigReportRspCmd( pInMsg );

break;case ZCL_CMD_READ_REPORT_CFG:// zclSampleLight_ProcessInReadReportCfgCmd( pInMsg );

break;case ZCL_CMD_READ_REPORT_CFG_RSP:// zclSampleLight_ProcessInReadReportCfgRspCmd( pInMsg );

break;case ZCL_CMD_REPORT:// zclSampleLight_ProcessInReportCmd( pInMsg );

break;...

typedef struct

{osal_event_hdr_t hdr;zclFrameHdr_t zclHdr;uint16 clusterId;afAddrType_t srcAddr;uint8 endPoint;void *attrCmd;

} zclIncomingMsg_t;

Page 5: Implementation of the ZigBee ZCL Reporting Configuration Features

5

Our Goal

Make SampleLight application support the ZCL features of

◦ ZCL_CMD_CONFIG_REPORT

◦ ZCL_CMD_READ_REPORT_CFG

◦ ZCL_CMD_REPORT

SampleLight App

attr_1

attr_2

attr_N

ZCL_CMD_CONFIG_REPORT

ZCL_CMD_CONFIG_REPORT_RSP

ZCL_CMD_READ_REPORT_CFG

ZCL_CMD_READ_REPORT_CFG_RSP

ARemote

ZigBee

Device

Device A: “I want you to report your

attr_1 and attr_2 in every X

seconds, or upon changing”

B

C

SampleLight: “OK, attr_1 and attr_2

are configured to

report as your request.”

Device B: “Please tell me about your

reporting configurations of

attr_1 and attr_3.”

SampleLight: “My attr_1 is reportable

and attr_3 is unreportable.”

Device C: “Please report your attr_1.”

� �

Page 6: Implementation of the ZigBee ZCL Reporting Configuration Features

6

Firmware

Stack version

◦ Z-Stack Home 1.2.1 / 1.2.2 ( http://www.ti.com/tool/z-stack )

Code to modify

◦ C:\Texas Instruments\Z-Stack Home 1.2.1

� \Components\stack\zcl

� zcl.h

� zcl.c

� \Projects\zstack\HomeAutomation\SampleLight\Source

� zcl_samplelight_data.c

� zcl_samplelight.h

� zcl_samplelight.c

� https://github.com/sivann/samplelight_cfgreport

Page 7: Implementation of the ZigBee ZCL Reporting Configuration Features

7

zcl.h

◦ Define two data types:

� zclConfigReportRec_t : “Reporting config. record” for an endpoint

� zclConfigReportRecsList : “Reporting config. records list” of all endpoints

zcl.c

◦ A function to register the “Reporting config. table”.

� zcl_registerConfigReportRecList()

zcl_samplelight_data.c

◦ Add Config. Report Records to zcl_samplelight_data.c

� zclConfigReportRec_t zclSampleLight_ConfigReportRecs[]

zcl_samplelight.h, zcl_samplelight.c

◦ Implementation of zcl attribute reporting features

Steps

Page 8: Implementation of the ZigBee ZCL Reporting Configuration Features

8

zcl.h: New Data Types

/*********************************************************************

* TYPEDEFS

*/

// Configure Reporting Command format

...

} zclCfgReportRec_t;

typedef struct

{uint16 clusterId;uint16 timeup; uint8 *lastReportValue;zclCfgReportRec_t cfgReportRec;

} zclConfigReportRec_t;

/*********************************************************************

* CONSTANTS

*/

...

#define ZCL_FRAME_SERVER_CLIENT_DIR 0x01

/*** Report SEND/RECEIVE Directions ***/

#define ZCL_REPORT_SEND 0x00

#define ZCL_REPORT_RECEIVE 0x01

#ifdef ZCL_REPORT

// Config Report record list item

typedef struct zclConfigReportRecsList

{struct zclConfigReportRecsList *next;uint8 endpoint;uint8 numConfigReportRec;zclConfigReportRec_t *configReportRecs;

} zclConfigReportRecsList;#endif // ZCL_REPORT

� zclConfigReportRec_t

� zclConfigReportRecsList

Page 9: Implementation of the ZigBee ZCL Reporting Configuration Features

9

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRecsList

*next

endpoint

numConfigReportRec

*configReportRecs

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRecsList

*next

endpoint

numConfigReportRec

*configReportRecs

Rec_1 Rec_2 Rec_3

Rec_1 Rec_2 Rec_3

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRecsList

*next

endpoint

numConfigReportRec

*configReportRecs

Rec_1 Rec_2 Rec_3

List_for_Endpoint_1

List_for_Endpoint_2

List_for_Endpoint_3

Page 10: Implementation of the ZigBee ZCL Reporting Configuration Features

10

zcl.h: Declare Local Variables and Functions

/*********************************************************************

* FUNCTIONS

*/

[...]

extern ZStatus_t zcl_registerAttrList( uint8 endpoint, uint8 numAttr,CONST zclAttrRec_t attrList[] );

#ifdef ZCL_REPORT

/* Register Application's Config Report table */

extern ZStatus_t zcl_registerConfigReportRecList( uint8 endpoint, uint8 numConfigReportRec,zclConfigReportRec_t newConfigReportRecList[] );

#endif // ZCL_REPORT

#ifdef ZCL_REPORT

[...]

extern uint8 zclAnalogDataType( uint8 dataType );[...]

/* Function to find the Config Report Record of an Atribute that matches the parameters */

extern uint8 zclFindConfigReportRec( uint8 endpoint, uint16 clusterID, uint16 attrId,zclConfigReportRec_t **pConfigReportRec );

extern zclConfigReportRecsList *zclFindConfigReportRecsList( uint8 endpoint );#endif // ZCL_REPORT

Page 11: Implementation of the ZigBee ZCL Reporting Configuration Features

11

Prototype of the Config. Table Register Function

zcl.c: Config. Table Register Function (I)

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRecsList

*next

endpoint

numConfigReportRec

*configReportRecs

Rec_1 Rec_2 Rec_3

ZStatus_t zcl_registerConfigReportRecList( uint8 endpoint,

uint8 numConfigReportRec,

zclConfigReportRec_t newConfigReportRecList[] )

Page 12: Implementation of the ZigBee ZCL Reporting Configuration Features

12

zcl.c: Config. Table Register Function (II)

[...]

ZStatus_t zcl_registerCmdList( uint8 endpoint, CONST uint8 cmdListSize,CONST zclCommandRec_t newCmdList[] )

{[...]

}#endif // ZCL_DISCOVER

#ifdef ZCL_REPORT

/*********************************************************************

* @fn zcl_registerConfigReportRecList

* @brief Register an ConfigReportRec List with ZCL Foundation

* @param endpoint - endpoint the attribute list belongs to

* @param numConfigReportRec - number of attributes in list

* @param newConfigReportRecList - array of Attribute records.

* @return ZSuccess if OK

*/

ZStatus_t zcl_registerConfigReportRecList( uint8 endpoint, uint8 numConfigReportRec,zclConfigReportRec_t newConfigReportRecList[] )

{zclConfigReportRecsList *pNewItem;zclConfigReportRecsList *pLoop;

// Fill in the new profile list

pNewItem = zcl_mem_alloc( sizeof( zclConfigReportRecsList ) );if ( pNewItem == NULL ){return (ZMemError);

}

Page 13: Implementation of the ZigBee ZCL Reporting Configuration Features

13

pNewItem->next = (zclConfigReportRecsList *)NULL;pNewItem->endpoint = endpoint;pNewItem->numConfigReportRec = numConfigReportRec;pNewItem->configReportRecs = newConfigReportRecList;

// Find spot in list

if ( configReportRecsList == NULL ){configReportRecsList = pNewItem;

}else{// Look for end of list

pLoop = configReportRecsList;while ( pLoop->next != NULL ){pLoop = pLoop->next;

}

// Put new item at end of list

pLoop->next = pNewItem;}

return ( ZSuccess );}#endif // ZCL_REPORT

Page 14: Implementation of the ZigBee ZCL Reporting Configuration Features

14

Prototype of the Config. Report Recs List Searching

Function

Prototype of the Config. Report Rec Searching Function

zcl.c: Config. Record Searching Function

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRec_t

clusterId

timeup

*lastReportValue

cfgReportRec

zclConfigReportRecsList

*next

endpoint

numConfigReportRec

*configReportRecs

Rec_1 Rec_2 Rec_3

zclConfigReportRecsList *zclFindConfigReportRecsList( uint8 endpoint )

uint8 zclFindConfigReportRec( uint8 endpoint, uint16 clusterID,uint16 attrId,zclConfigReportRec_t **pConfigReportRec )

Page 15: Implementation of the ZigBee ZCL Reporting Configuration Features

15

Config. Report Recs List Searching Function

/*********************************************************************

* PRIVATE FUNCTIONS

*********************************************************************/

[...]

#ifdef ZCL_REPORT

/*********************************************************************

* @fn zclFindConfigReportRecsList

* @brief Find the right ConfigReport record list for an endpoint

* @param clusterID - endpoint to look for

* @return pointer to record list, NULL if not found

*/

zclConfigReportRecsList *zclFindConfigReportRecsList( uint8 endpoint ){

zclConfigReportRecsList *pLoop = configReportRecsList;

while ( pLoop != NULL ){if ( pLoop->endpoint == endpoint ){return ( pLoop );

}

pLoop = pLoop->next;}

return ( NULL );}

Page 16: Implementation of the ZigBee ZCL Reporting Configuration Features

16

/*********************************************************************

* @fn zclFindConfigReportRec

* @brief Find the configReportRec record that matches the parameters

* @param endpoint - Application's endpoint

* @param clusterID - cluster ID

* @param attrId - attribute looking for

* @param pConfigReportRec - ConfigReportRec record to be returned

* @return TRUE if record found. FALSE, otherwise.

*/

uint8 zclFindConfigReportRec( uint8 endpoint, uint16 clusterID, uint16 attrId,zclConfigReportRec_t **pConfigReportRec )

{uint8 x;zclConfigReportRecsList *pRec = zclFindConfigReportRecsList( endpoint );

if ( pRec != NULL ){for ( x = 0; x < pRec->numConfigReportRec; x++ ){if ( pRec->configReportRecs[x].clusterId ==

clusterID && pRec->configReportRecs[x].cfgReportRec.attrID == attrId ){*pConfigReportRec = &(pRec->configReportRecs[x]);return ( TRUE );

}}

}return ( FALSE );

}#endif // ZCL_REPORT

Config. Report Rec Searching Function

Page 17: Implementation of the ZigBee ZCL Reporting Configuration Features

17

zcl.c is ready. Now, we’re going to name the attributes

from clusters to be configured for reporting.

zcl_sampleligh_data.c: Arrangement

/*********************************************************************

* GLOBAL VARIABLES

*/

const uint8 zclSampleLight_HWRevision = SAMPLELIGHT_HWVERSION;[...]

uint8 zclSampleLight_OnOffLastReportValue = LIGHT_OFF;

#ifdef ZCL_LEVEL_CTRL

uint8 zclSampleLight_LevelCurrentLevel = ATTR_LEVEL_MIN_LEVEL;

uint8 zclSampleLight_LevelCurrentLevelChange = 50;uint8 zclSampleLight_LevelLastReportValue = ATTR_LEVEL_MIN_LEVEL;[...]

#endif

#ifdef ZCL_REPORT

zclConfigReportRec_t zclSampleLight_ConfigReportRecs[] ={// See Next Slide

{...

Page 18: Implementation of the ZigBee ZCL Reporting Configuration Features

18

typedef struct

{uint16 clusterId;uint16 timeup; uint8 *lastReportValue;zclCfgReportRec_t cfgReportRec;

} zclConfigReportRec_t;

typedef struct

{uint8 direction;uint16 attrID;uint8 dataType;uint16 minReportInt;uint16 maxReportInt;uint16 timeoutPeriod;uint8 *reportableChange;

} zclCfgReportRec_t;

zclConfigReportRec_t zclSampleLight_ConfigReportRecs[] ={ // *** On/Off Cluster Attr ConfigReportRec ***{ZCL_CLUSTER_ID_GEN_ON_OFF,0xFFFF,(void *)&zclSampleLight_OnOffLastReportValue,{ // CfgReportRecZCL_REPORT_SEND,ATTRID_ON_OFF,ZCL_DATATYPE_BOOLEAN,0,0xFFFF,0,NULL // need not set for

} // DISCRETE datatype}

#ifdef ZCL_LEVEL_CTRL,{ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL,0xFFFF,(void *)&zclSampleLight_LevelLastReportValue,{ZCL_REPORT_SEND,ATTRID_LEVEL_CURRENT_LEVEL,ZCL_DATATYPE_UINT8,0,0xFFFF,0,(void *)&zclSampleLight_LevelCurrentLevelChange

}}

#endif

};

uint8 CONST zclSampleLight_NumConfigReportRecs =( sizeof(zclSampleLight_ConfigReportRecs) / sizeof(zclSampleLight_ConfigReportRecs[0]) );

#endif

timeup

clusterId

*lastReportValue

direction

attrID

dataType

minReportInt

maxReportInt

timeoutPeroid

*reportableChange

Page 19: Implementation of the ZigBee ZCL Reporting Configuration Features

19

zcl_samplelight.h: Declarations

/*********************************************************************

* VARIABLES

*/

[...]

extern CONST uint8 zclCmdsArraySize;extern CONST uint8 zclSampleLight_NumConfigReportRecs;extern zclConfigReportRec_t zclSampleLight_ConfigReportRecs[];[...]

// OnOff attributes

extern uint8 zclSampleLight_OnOff;

extern uint8 zclSampleLight_OnOffLastReportValue;

// Level Control Attributes

#ifdef ZCL_LEVEL_CTRL

[...]

extern uint8 zclSampleLight_LevelCurrentLevelChange;extern uint8 zclSampleLight_LevelLastReportValue;#endif

/*********************************************************************

* CONSTANTS

*/

#define SAMPLELIGHT_ENDPOINT 8

[...]

// Application Events

#define SAMPLELIGHT_IDENTIFY_TIMEOUT_EVT 0x0001

[...]

#define SAMPLELIGHT_START_EZMODE_EVT 0x0040

#define SAMPLELIGHT_CHECK_REPORT_EVT 0x0080

Page 20: Implementation of the ZigBee ZCL Reporting Configuration Features

20

zcl_samplelight.c : Declarations

/*********************************************************************

* LOCAL VARIABLES

*/

afAddrType_t zclSampleLight_DstAddr;

uint16 gTimeCounter = 0;

/*********************************************************************

* LOCAL FUNCTIONS

*/

#ifdef ZCL_LEVEL_CTRL

[...]

static void sendZclAttrChangeReport(uint8 srcEp, uint16 clusterId, uint16 attrID,uint8 *lastReportValue, uint8 *currentValue);

#endif

[...]

#ifdef ZCL_REPORT

[...]

static void zclSampleLight_CheckReportConfig( void );static uint8 sendZclAttrReport(uint8 srcEp, uint16 clusterID, zclReportCmd_t *pReportCmd,

uint8 dataLen);static void zclSampleLight_CheckandSendClusterAttrReport( uint16 clusterID,

zclConfigReportRecsList *pConfigReportRecsList );#endif

Page 21: Implementation of the ZigBee ZCL Reporting Configuration Features

21

zcl_samplelight.c : Register the Report Recs

void zclSampleLight_Init( byte task_id ){zclSampleLight_TaskID = task_id;[...]

// Register the application's attribute list

zcl_registerAttrList( SAMPLELIGHT_ENDPOINT, zclSampleLight_NumAttributes,zclSampleLight_Attrs );

#ifdef ZCL_REPORT

// Register the application's config report record list

zcl_registerConfigReportRecList( SAMPLELIGHT_ENDPOINT, zclSampleLight_NumConfigReportRecs,zclSampleLight_ConfigReportRecs );

#endif

// Register the Application to receive the unprocessed Foundation command/response messages

zcl_registerForMsg( zclSampleLight_TaskID );[...]

}

Page 22: Implementation of the ZigBee ZCL Reporting Configuration Features

22

Arrange an event handler (for event: SAMPLELIGHT_CHECK_REPORT_EVT)

to check if there is a reportable timeout attribute.

zcl_samplelight.c: Event Handler

uint16 zclSampleLight_event_loop( uint8 task_id, uint16 events ){[...]

#ifdef ZCL_LEVEL_CTRL

if ( events & SAMPLELIGHT_LEVEL_CTRL_EVT ){zclSampleLight_AdjustLightLevel();return ( events ^ SAMPLELIGHT_LEVEL_CTRL_EVT );

}#endif

#ifdef ZCL_REPORT

if ( events & SAMPLELIGHT_CHECK_REPORT_EVT ){zclSampleLight_CheckReportConfig( &zclSampleLightSeqNum );return ( events ^ SAMPLELIGHT_CHECK_REPORT_EVT );

}#endif

// Discard unknown events

return 0;}

Page 23: Implementation of the ZigBee ZCL Reporting Configuration Features

23

Check If an Reportable Attribute is Timeout#ifdef ZCL_REPORT

/*********************************************************************

* @fn zclSampleLight_CheckReportConfig

* @brief Check if there is a reportable attribute is timeout to report

* @param none

* @return none

*/

static void zclSampleLight_CheckReportConfig( void ){uint8 x, y;uint8 stopChecking = TRUE;

zclConfigReportRecsList *pConfigReportRecsList = zclFindConfigReportRecsList(SAMPLELIGHT_ENDPOINT);if ( pConfigReportRecsList != NULL ){for ( x = 0; x < pConfigReportRecsList->numConfigReportRec; x++ ){

uint8 cIdDuplicate = 0;for ( y = 0; y < x; y++ ){

if ( pConfigReportRecsList->configReportRecs[x].clusterId ==pConfigReportRecsList->configReportRecs[y].clusterId ) {cIdDuplicate = 1;

}}

if (!cIdDuplicate) {zclSampleLight_CheckandSendClusterAttrReport( pConfigReportRecsList->

configReportRecs[x].clusterId, pConfigReportRecsList );}

Page 24: Implementation of the ZigBee ZCL Reporting Configuration Features

24

if (pConfigReportRecsList->configReportRecs[x].cfgReportRec.maxReportInt != 0xFFFF) {stopChecking = FALSE; // at least one attr in this endpoint is setting to report,

} // don't stop checking}

}

gTimeCounter++; // time ticks every second for attr report

if (!stopChecking) {osal_start_timerEx( zclSampleLight_TaskID, SAMPLELIGHT_CHECK_REPORT_EVT, 1000 );

}}

static void zclSampleLight_CheckandSendClusterAttrReport( uint16 clusterID,zclConfigReportRecsList *pConfigReportRecsList )

{uint8 numAttr = 0;uint8 x;uint16 len;zclReportCmd_t *pReportCmd;zclConfigReportRec_t *pConfigReportRec = NULL;zclAttrRec_t attrRec;

for ( x = 0; x < pConfigReportRecsList->numConfigReportRec; x++ ){

pConfigReportRec = &(pConfigReportRecsList->configReportRecs[x]);// find out how many attributes are timeout in this cluster

if ( pConfigReportRec->clusterId == clusterID && pConfigReportRec->cfgReportRec.maxReportInt != 0xFFFF) {

if (pConfigReportRec->timeup == 0xFFFF || pConfigReportRec->timeup == gTimeCounter){

numAttr++;}

}}

Page 25: Implementation of the ZigBee ZCL Reporting Configuration Features

25

if (numAttr != 0) {// We need to send a report - allocate space for it

len = sizeof( zclReportCmd_t ) + (numAttr * sizeof( zclReport_t ));pReportCmd = (zclReportCmd_t *)zcl_mem_alloc( len );pReportCmd->numAttr = numAttr;

}numAttr = 0;

for ( x = 0; x < pConfigReportRecsList->numConfigReportRec; x++ ){

zclReport_t *reportRec;pConfigReportRec = &(pConfigReportRecsList->configReportRecs[x]);

if ( pConfigReportRec->clusterId == clusterID && pConfigReportRec->cfgReportRec.maxReportInt != 0xFFFF) // need report

{ // timeout to reportif (pConfigReportRec->timeup == 0xFFFF || pConfigReportRec->timeup == gTimeCounter){

// fill the record in *pReportCmd

reportRec = &(pReportCmd->attrList[numAttr]);zcl_memset( reportRec, 0, sizeof( zclReport_t ) );numAttr++;zclFindAttrRec( SAMPLELIGHT_ENDPOINT, pConfigReportRec->clusterId,

pConfigReportRec->cfgReportRec.attrID, &attrRec);reportRec->attrID = attrRec.attr.attrId;reportRec->dataType = attrRec.attr.dataType;reportRec->attrData = attrRec.attr.dataPtr;

Page 26: Implementation of the ZigBee ZCL Reporting Configuration Features

26

// calculate next timeout value

if (pConfigReportRec->cfgReportRec.minReportInt == 0) {pConfigReportRec->timeup = gTimeCounter +

pConfigReportRec->cfgReportRec.maxReportInt;} else {

pConfigReportRec->timeup = gTimeCounter +pConfigReportRec->cfgReportRec.minReportInt;

}}

}}

if (numAttr != 0) {// send report

sendZclAttrReport( SAMPLELIGHT_ENDPOINT, clusterID, pReportCmd, len);}

}#endif

static uint8 sendZclAttrReport(uint8 srcEp, uint16 clusterID, zclReportCmd_t *pReportCmd,uint8 dataLen)

{zclIncomingMsg_t *pMsg; // this is for inner-app osal msg, not OTA msg,

// thus we will see that some fields are not important

// pMsg will be released by zclSampleLight_event_loop()

pMsg = (zclIncomingMsg_t *)osal_msg_allocate( sizeof(zclIncomingMsg_t) + (dataLen));

if ( pMsg == NULL ){return FALSE; // EMBEDDED RETURN

}

Page 27: Implementation of the ZigBee ZCL Reporting Configuration Features

27

if (pMsg) // inner-app osal message

{pMsg->hdr.event = ZCL_INCOMING_MSG;pMsg->hdr.status = 0;//pMsg->zclHdr.fc = NULL; // not important

pMsg->zclHdr.manuCode = 0; // not important

pMsg->zclHdr.transSeqNum = 0; // not important

pMsg->zclHdr.commandID = ZCL_CMD_REPORT; // send this report message to ZCL_CMD_REPORT // event handler

pMsg->clusterId = clusterID;pMsg->srcAddr.addrMode = (afAddrMode_t)Addr16Bit;pMsg->srcAddr.addr.shortAddr = 0; // not important

pMsg->srcAddr.panId = 0; // inner-PAN, not important

pMsg->srcAddr.endPoint = srcEp; // src ep, SAMPLELIGHT_ENDPOINT send to himself

pMsg->endPoint = srcEp; // dest ep, send to SAMPLELIGHT_ENDPOINT himself

pMsg->attrCmd = (zclReportCmd_t *)pReportCmd;}

osal_msg_send( zclSampleLight_TaskID, (uint8 *)pMsg );

return ( TRUE );}

case ZCL_CMD_REPORT:zclSampleLight_ProcessInReportCmd( pInMsg );break;

Page 28: Implementation of the ZigBee ZCL Reporting Configuration Features

28

Call sendZclAttrChangeReport() to send out the

current attribute.

When the Reportable Attribute is Changed

static void zclSampleLight_HandleKeys( byte shift, byte keys ){if ( keys & HAL_KEY_SW_1 ) {

giLightScreenMode = LIGHT_MAINMODE;

if (zclSampleLight_OnOffLastReportValue != zclSampleLight_OnOff) {sendZclAttrChangeReport(SAMPLELIGHT_ENDPOINT, ZCL_CLUSTER_ID_GEN_ON_OFF, ATTRID_ON_OFF,

&zclSampleLight_OnOffLastReportValue, &zclSampleLight_OnOff);}

}

[...]

static void zclSampleLight_OnOffCB( uint8 cmd ){[...]

else if ( cmd == COMMAND_TOGGLE ) {[...]

}

if (zclSampleLight_OnOffLastReportValue != zclSampleLight_OnOff) {sendZclAttrChangeReport(SAMPLELIGHT_ENDPOINT, ZCL_CLUSTER_ID_GEN_ON_OFF, ATTRID_ON_OFF,

&zclSampleLight_OnOffLastReportValue, &zclSampleLight_OnOff);}

[...]

Page 29: Implementation of the ZigBee ZCL Reporting Configuration Features

29

static void zclSampleLight_AdjustLightLevel( void ){uint8 needReport = FALSE;[...]

if ( zclSampleLight_LevelRemainingTime == 0)

{

zclSampleLight_LevelCurrentLevel = zclSampleLight_NewLevel;

// check if we need to report by change

if (zclSampleLight_LevelLastReportValue > zclSampleLight_LevelCurrentLevel) {if (zclSampleLight_LevelLastReportValue - zclSampleLight_LevelCurrentLevel

>= zclSampleLight_LevelCurrentLevelChange) {needReport = TRUE;

}} else {

if (zclSampleLight_LevelCurrentLevel - zclSampleLight_LevelLastReportValue

>= zclSampleLight_LevelCurrentLevelChange) {needReport = TRUE;

}}

if (needReport) {sendZclAttrChangeReport(SAMPLELIGHT_ENDPOINT, ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL,

ATTRID_LEVEL_CURRENT_LEVEL,&zclSampleLight_LevelLastReportValue,&zclSampleLight_LevelCurrentLevel);

}}

Page 30: Implementation of the ZigBee ZCL Reporting Configuration Features

30

/*********************************************************************

* @fn sendZclAttrChangeReport

* @brief Send the attr report when the attr is changed

* @param srcEp - source endpoint

[...]

static void sendZclAttrChangeReport(uint8 srcEp, uint16 clusterId, uint16 attrID,uint8 *lastReportValue, uint8 *currentValue) {

if (*lastReportValue != *currentValue){ // if the current attr value is not equal to the last reported value, report the change

zclReportCmd_t *pReportCmd;zclReport_t *reportRec;zclAttrRec_t attrRec;uint8 len;

len = sizeof( zclReportCmd_t ) + (1 * sizeof( zclReport_t ));pReportCmd = (zclReportCmd_t *)zcl_mem_alloc( len );pReportCmd->numAttr = 1;

reportRec = &(pReportCmd->attrList[0]);zcl_memset( reportRec, 0, sizeof( zclReport_t ) );zclFindAttrRec( SAMPLELIGHT_ENDPOINT, clusterId, attrID, &attrRec);

reportRec->attrID = attrRec.attr.attrId;reportRec->dataType = attrRec.attr.dataType;reportRec->attrData = attrRec.attr.dataPtr;

sendZclAttrReport(SAMPLELIGHT_ENDPOINT, clusterId, pReportCmd, len);

*lastReportValue = *currentValue;}

}

Page 31: Implementation of the ZigBee ZCL Reporting Configuration Features

31

When We Got a Report Cmd

static uint8 zclSampleLight_ProcessInReportCmd( zclIncomingMsg_t *pInMsg ){zclReportCmd_t *pReportCmd;// *pReportCmd will be free by handler: zclSampleLight_ProcessIncomingMsg()

pReportCmd = (zclReportCmd_t *)pInMsg->attrCmd;afAddrType_t dstAddr;

dstAddr.addrMode = (afAddrMode_t)AddrNotPresent; // send report to bound remote endpoints

zcl_SendReportCmd( SAMPLELIGHT_ENDPOINT, &dstAddr, pInMsg->clusterId, pReportCmd,ZCL_REPORT_SEND, true, zclSampleLightSeqNum++);

// you can send additional reportable attributes as needed

/** zcl_SendReportCmd ( SAMPLELIGHT_ENDPOINT, &dstAddr, ...); **/

// i.e. for Thermostat Cluster that reports LocalTemperature, PICoolingDemand, and PIHeatingDemand.

// see ZIGBEE CLUSTER LIBRARY SPECIFICATION: 6.3.2.5 Attribute Reporting of the Thermostat Cluster

return ( TRUE );}

Page 32: Implementation of the ZigBee ZCL Reporting Configuration Features

32

When We Got a Config Report Cmd#ifdef ZCL_REPORT

/*********************************************************************

* @fn zclSampleLight_ProcessInConfigReportCmd

* @brief Process the "Profile" Config Report Command

* @param pInMsg - incoming message to process

* @return none

*/

static uint8 zclSampleLight_ProcessInConfigReportCmd( zclIncomingMsg_t *pInMsg ){zclCfgReportCmd_t *pCfgReportCmd;zclCfgReportRspCmd_t *pCfgReportRspCmd;uint8 sendRsp = FALSE;uint16 len;uint8 j = 0;uint8 i;

pCfgReportCmd = (zclCfgReportCmd_t *)pInMsg->attrCmd;

if ( pInMsg->zclHdr.commandID == ZCL_CMD_CONFIG_REPORT ){

// We need to send a response back - allocate space for it

len = sizeof( zclCfgReportRspCmd_t ) + (pCfgReportCmd->numAttr *sizeof( zclCfgReportStatus_t ));

pCfgReportRspCmd = (zclCfgReportRspCmd_t *)zcl_mem_alloc( len );

if ( pCfgReportRspCmd == NULL ) {return FALSE; // EMBEDDED RETURN

}sendRsp = TRUE; // sendRsp is active when we got correct commandID

}

Page 33: Implementation of the ZigBee ZCL Reporting Configuration Features

33

for ( i = 0; i < pCfgReportCmd->numAttr; i++ ){zclConfigReportRec_t *pConfigReportRec = NULL; // find the rec and store here

zclAttrRec_t attrRec;

zclCfgReportStatus_t *statusRec = &(pCfgReportRspCmd->attrList[i]);zcl_memset( statusRec, 0, sizeof( zclCfgReportStatus_t ) );

if ( zclFindConfigReportRec( pInMsg->endPoint, pInMsg->clusterId,pCfgReportCmd->attrList[i].attrID, &pConfigReportRec ) )

{uint8 status = ZCL_STATUS_SUCCESS;

if ( pCfgReportCmd->attrList[i].dataType != pConfigReportRec->cfgReportRec.dataType ) {status = ZCL_STATUS_INVALID_DATA_TYPE;

}else{

if ( zclFindAttrRec( pInMsg->endPoint, pInMsg->clusterId,pCfgReportCmd->attrList[i].attrID, &attrRec ) )

{if ( pCfgReportCmd->attrList[i].dataType != attrRec.attr.dataType ) {

status = ZCL_STATUS_INVALID_DATA_TYPE;}else{

if ( !zcl_AccessCtrlRead( attrRec.attr.accessControl ) ){status = ZCL_STATUS_WRITE_ONLY;

}}

}}

Page 34: Implementation of the ZigBee ZCL Reporting Configuration Features

34

// If successful, store the record, and a CfgReportStatus record shall NOT be generated

if ( sendRsp && status != ZCL_STATUS_SUCCESS ){

// Attribute is write only or invalid data type - move on to the next record

statusRec->status = status;statusRec->direction = pCfgReportCmd->attrList[i].direction;statusRec->attrID = pCfgReportCmd->attrList[i].attrID;j++;

} else { // success, set the config report rec

pConfigReportRec->cfgReportRec.direction = pCfgReportCmd->attrList[i].direction;pConfigReportRec->cfgReportRec.minReportInt = pCfgReportCmd->attrList[i].minReportInt;pConfigReportRec->cfgReportRec.maxReportInt = pCfgReportCmd->attrList[i].maxReportInt;pConfigReportRec->cfgReportRec.timeoutPeriod = pCfgReportCmd->attrList[i].timeoutPeriod;pConfigReportRec->timeup = 0xFFFF;

}}else{ // Attribute is not supported - move on to the next configReportRec record

if ( sendRsp ){statusRec->status = ZCL_STATUS_UNSUPPORTED_ATTRIBUTE;statusRec->direction = pCfgReportCmd->attrList[i].direction;statusRec->attrID = pCfgReportCmd->attrList[i].attrID;j++;

}}

} // for loop

Page 35: Implementation of the ZigBee ZCL Reporting Configuration Features

35

if ( sendRsp ){pCfgReportRspCmd->numAttr = j;if ( pCfgReportRspCmd->numAttr == 0 ){// Since all records were written successful, include a single status record

// in the response command with the status field set to SUCCESS and the

// attribute ID and direction fields omitted.

pCfgReportRspCmd->attrList[0].status = ZCL_STATUS_SUCCESS;pCfgReportRspCmd->numAttr = 1;

}

zcl_SendConfigReportRspCmd( pInMsg->endPoint, &(pInMsg->srcAddr),pInMsg->clusterId, pCfgReportRspCmd,

!pInMsg->zclHdr.fc.direction, true,pInMsg->zclHdr.transSeqNum );

zcl_mem_free( pCfgReportRspCmd );}

// When configured, check report config immediately

zclSampleLight_CheckReportConfig();

// The SAMPLELIGHT_CHECK_REPORT_EVT will then be triggered again and again

// If we never received the ConfigReportCmd, the SAMPLELIGHT_CHECK_REPORT_EVT has

// no change to be triggered.

// We think this makes sense, since there is no reason for your app to perform

// constantly report unless the app is configured to report.

// If your app just need to automatically report after bootup, you can trigger

// SAMPLELIGHT_CHECK_REPORT_EVT in zclSampleLight_Init().

return TRUE;}

Page 36: Implementation of the ZigBee ZCL Reporting Configuration Features

36

When We Got a Read Report Config Cmd

/*********************************************************************

* @fn zclSampleLight_ProcessInReadReportCfgCmd

* @brief Process the "Profile" Read Report Config Command

* @param pInMsg - incoming message to process

* @return none

*/

static uint8 zclSampleLight_ProcessInReadReportCfgCmd( zclIncomingMsg_t *pInMsg ){zclReadReportCfgCmd_t *pReadReportCfgCmd;zclReadReportCfgRspCmd_t *pReadReportCfgRspCmd;uint8 sendRsp = FALSE;uint16 len;uint8 i;

pReadReportCfgCmd = (zclReadReportCfgCmd_t *)pInMsg->attrCmd;

if ( pInMsg->zclHdr.commandID == ZCL_CMD_READ_REPORT_CFG ){// We need to send a response back - allocate space for it

len = sizeof( zclReadReportCfgRspCmd_t ) + (pReadReportCfgCmd->numAttr *sizeof( zclReportCfgRspRec_t ));

pReadReportCfgRspCmd = (zclReadReportCfgRspCmd_t *)zcl_mem_alloc( len );

if ( pReadReportCfgRspCmd == NULL ) {return FALSE; // EMBEDDED RETURN

}

sendRsp = TRUE; // sendRsp is active when we got correct commandID

}

Page 37: Implementation of the ZigBee ZCL Reporting Configuration Features

37

for ( i = 0; i < pReadReportCfgCmd->numAttr; i++ ){zclConfigReportRec_t *pConfigReportRec = NULL; // find the rec and store here

zclReportCfgRspRec_t *pReportCfgRspRec = &(pReadReportCfgRspCmd->attrList[i]);zclAttrRec_t attrRec;

zcl_memset( pReportCfgRspRec, 0, sizeof( zclReportCfgRspRec_t ) );

if ( zclFindConfigReportRec( pInMsg->endPoint, pInMsg->clusterId,pReadReportCfgCmd->attrList[i].attrID, &pConfigReportRec ) )

{ // if found configReportRec

if ( sendRsp ) {pReportCfgRspRec->status = ZCL_STATUS_SUCCESS;pReportCfgRspRec->direction = pConfigReportRec->cfgReportRec.direction;pReportCfgRspRec->attrID = pConfigReportRec->cfgReportRec.attrID;pReportCfgRspRec->dataType = pConfigReportRec->cfgReportRec.dataType;pReportCfgRspRec->minReportInt = pConfigReportRec->cfgReportRec.minReportInt;pReportCfgRspRec->maxReportInt = pConfigReportRec->cfgReportRec.maxReportInt;pReportCfgRspRec->timeoutPeriod = pConfigReportRec->cfgReportRec.timeoutPeriod;pReportCfgRspRec->reportableChange = pConfigReportRec->cfgReportRec.reportableChange;

}}else{

// if not found configReportRec, check if the attribute is an un-reportable

// or an un-supported one

uint8 status = ZCL_STATUS_UNSUPPORTED_ATTRIBUTE;

if ( zclFindAttrRec( pInMsg->endPoint, pInMsg->clusterId,pReadReportCfgCmd->attrList[i].attrID, &attrRec ) )

{// if found the attr rec, it is there but un-reportable

status = ZCL_STATUS_UNREPORTABLE_ATTRIBUTE;}

Page 38: Implementation of the ZigBee ZCL Reporting Configuration Features

38

// Attribute is not supported - move on to the next configReportRec record

if ( sendRsp ){pReportCfgRspRec->status = status;pReportCfgRspRec->direction = pReadReportCfgCmd->attrList[i].direction;pReportCfgRspRec->attrID = pReadReportCfgCmd->attrList[i].attrID;

}}

} // for loop

if ( sendRsp ){pReadReportCfgRspCmd->numAttr = pReadReportCfgCmd->numAttr;

zcl_SendReadReportCfgRspCmd( pInMsg->endPoint, &(pInMsg->srcAddr), pInMsg->clusterId,pReadReportCfgRspCmd, !pInMsg->zclHdr.fc.direction, true,pInMsg->zclHdr.transSeqNum );

zcl_mem_free( pReadReportCfgRspCmd );}

return TRUE;}

/*********************************************************************

* @fn zclSampleLight_ProcessInReportCmd

*

[...]

#endif // ZCL_REPORT

Page 39: Implementation of the ZigBee ZCL Reporting Configuration Features

39

Don’t Forget to Uncomment Handlers

static void zclSampleLight_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg ){switch ( pInMsg->zclHdr.commandID ){[...]

#ifdef ZCL_REPORT

// Attribute Reporting implementation should be added here

case ZCL_CMD_CONFIG_REPORT:zclSampleLight_ProcessInConfigReportCmd( pInMsg );break;

case ZCL_CMD_CONFIG_REPORT_RSP:// zclSampleLight_ProcessInConfigReportRspCmd( pInMsg );

break;

case ZCL_CMD_READ_REPORT_CFG:zclSampleLight_ProcessInReadReportCfgCmd( pInMsg );break;

case ZCL_CMD_READ_REPORT_CFG_RSP:// zclSampleLight_ProcessInReadReportCfgRspCmd( pInMsg );

break;

case ZCL_CMD_REPORT:zclSampleLight_ProcessInReportCmd( pInMsg );break;

#endif

[...]

Page 40: Implementation of the ZigBee ZCL Reporting Configuration Features

40

Print out the time stamp and messages received by

the host.

You must perform ‘binding’ first, or you’ll not receive

anything. (Report is sending out with ‘AddrNotPresent‘, z-stack will find out the addresses of

the bound devices)

Test Results (I)

Cluster: GenOnOff (0x0006)

Attribute: OnOff (0x0000)

Reporting period = 3 secs

3 secs

3 secs

3 secs

3 secs

Cluster: GenOnOff (0x0006)

Attribute: OnOff (0x0000)

Reporting period = 5 secs

- Suddenly turn on or turn off the light

5 secs

5 secs

5 secs

Changing of the OnOff Attr.

was reported

Changing of the OnOff Attr.

was reported

Page 41: Implementation of the ZigBee ZCL Reporting Configuration Features

41

Test Results (II)

10 secs

10 secs

10 secs

Report of level changing

10 secs

10 secs

10 secs

10 secs

Report of level changing

10 secs

10 secsReport of level changing

Cluster: GenLevelControl (0x0008)

Attribute: CurrentLevel (0x0000)

Reporting period = 10 secs

Amount of Change to Report = 20

- Suddenly change the light level

∆ = 199 ∆ = 170

∆ = -10(not reported)

∆ = -160

Page 42: Implementation of the ZigBee ZCL Reporting Configuration Features

42

[1] Z-Stack ZigBee Cluster Library Application Programming Interface,

Texas Instruments

References