This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Sample code for ZCL Read Attributes Command



hi;

can anybody share a sample code for using  ZCL_CMD_READ and  ZCL_CMD_READ_RSP  in both side of communication ( client and server) ?

i have problem with these commands.

thank you.

  • You can use API zcl_SendRead to do ZCL attribute read.
  • hi YK Chen;
    i khow these functions.

    this my code @ client side( when sw_1 pressed, i will send a read cmd):
    /*****************************************************************************/
    if ( keys & HAL_KEY_SW_1 )
    {

    /***********************Send Read Cmd******************/
    /**************************mine************************/

    zclReadCmd_t *pReadCmd;
    ZStatus_t status;
    pReadCmd = osal_mem_alloc( sizeof(zclReadCmd_t)+sizeof(uint16));
    if ( pReadCmd != NULL )
    {
    pReadCmd->numAttr = 1;
    pReadCmd->attrID[0] = ATTRID_ON_OFF;
    status = zcl_SendRead( SW_ENDPOINT, &zclSw_DstAddr,ZCL_CLUSTER_ID_GEN_ON_OFF,pReadCmd,ZCL_FRAME_CLIENT_SERVER_DIR, 0, zclSwSeqNum);
    if(status == SUCCESS)
    {
    HAL_TOGGLE_LED1() ;
    }
    }
    osal_mem_free( pReadCmd );
    }
    /*************************************************************************************/



    and this is my code @ server side :


    static void zclLight1_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg )
    {
    switch ( pInMsg->zclHdr.commandID )
    {
    #ifdef ZCL_READ
    case ZCL_CMD_READ:
    zclLight1_ProcessInReadCmd(pInMsg);
    break;
    case ZCL_CMD_READ_RSP:
    zclLight1_ProcessInReadRspCmd( pInMsg );
    break;
    #endif

    ........

    }

    static uint8 zclLight1_ProcessInReadCmd( zclIncomingMsg_t *pInMsg )
    {

    HAL_TOGGLE_LED_Identify();

    return(TRUE);
    }



    i got nothing on Server side!!!
  • Do you use Ubiqua Packet Analyzer to check if read command is sent?
  • my Ubiqua Packet Analyzer trial version has been expired!!!
    but i use packet sniffer and when i press the key a packet sent OTA.
  • Please attach your sniffer log.
  • I see the read attribute command is sent correctly and your light responses it.

  • i set a breakpoint in my light program @static void zclLight1_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg ) . when the command is send, the program counter dosent jump to breakpoint!
    what do you think ?
  • zclLight1_ProcessIncomingMsg? Do you have another zclXXX_ProcessIncomingMsg?

  • hi;

    no,i just change it's name. i will attache my code's files.please check them.

    /**************************************************************************************************
      Filename:       zcl_LIGHT.c
      Revised:        $Date: 2014-10-24 16:04:46 -0700 (Fri, 24 Oct 2014) $
      Revision:       $Revision: 40796 $
    
    
      Description:    Zigbee Cluster Library - sample device application.
    
    
      Copyright 2006-2014 Texas Instruments Incorporated. All rights reserved.
    
      IMPORTANT: Your use of this Software is limited to those specific rights
      granted under the terms of a software license agreement between the user
      who downloaded the software, his/her employer (which must be your employer)
      and Texas Instruments Incorporated (the "License").  You may not use this
      Software unless you agree to abide by the terms of the License. The License
      limits your use, and you acknowledge, that the Software may not be modified,
      copied or distributed unless embedded on a Texas Instruments microcontroller
      or used solely and exclusively in conjunction with a Texas Instruments radio
      frequency transceiver, which is integrated into your product.  Other than for
      the foregoing purpose, you may not use, reproduce, copy, prepare derivative
      works of, modify, distribute, perform, display or sell this Software and/or
      its documentation for any purpose.
    
      YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
      PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
      INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
      NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
      TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
      NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
      LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
      INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
      OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
      OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
      (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
    
      Should you have any questions regarding your right to use this Software,
      contact Texas Instruments Incorporated at www.TI.com.
    **************************************************************************************************/
    
    /*********************************************************************
      This application implements a ZigBee HA 1.2 Light. It can be configured as an
      On/Off light, or as a dimmable light. The following flags must be defined in
      the compiler's pre-defined symbols.
    
      ZCL_ON_OFF
      ZCL_LEVEL_CTRL    (only if dimming functionality desired)
      HOLD_AUTO_START
      ZCL_EZMODE
    
      This device supports all mandatory and optional commands/attributes for the
      OnOff (0x0006) and LevelControl (0x0008) clusters.
    
      SCREEN MODES
      ----------------------------------------
      Main:
        - SW1: Toggle local light
        - SW2: Invoke EZMode
        - SW4: Enable/Disable local permit join
        - SW5: Go to Help screen
      ----------------------------------------
    *********************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    #include "ZComDef.h"
    #include "OSAL.h"
    #include "AF.h"
    #include "ZDApp.h"
    #include "ZDObject.h"
    #include "MT_SYS.h"
    
    #include "nwk_util.h"
    
    #include "zcl.h"
    #include "zcl_general.h"
    #include "zcl_ha.h"
    #include "zcl_ezmode.h"
    #include "zcl_diagnostic.h"
    
    #include "zcl_MultiSensor.h"
    
    #include "onboard.h"
    
    /* HAL */
    #include "hal_lcd.h"
    #include "hal_led.h"
    #include "hal_key.h"
    
    /*mine*/
    #include "zcl_ms.h"
    #include "hal_adc.h"
    #include "aps_groups.h"   
    #include <stdio.h>
    
    /*************************/   
    
    #if ( defined (ZGP_DEVICE_TARGET) || defined (ZGP_DEVICE_TARGETPLUS) \
          || defined (ZGP_DEVICE_COMBO) || defined (ZGP_DEVICE_COMBO_MIN) )
    #include "zgp_translationtable.h"
      #if (SUPPORTED_S_FEATURE(SUPP_ZGP_FEATURE_TRANSLATION_TABLE))
        #define ZGP_AUTO_TT
      #endif
    #endif
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    #include "math.h"
    #include "hal_timer.h"
    #endif
    
    #include "NLMEDE.h"
    
    
    
    
    /*********************************************************************
     * MACROS
     */
    
    /*********************************************************************
     * CONSTANTS
     */
    #if (defined HAL_BOARD_ZLIGHT)
    #define LEVEL_MAX                 0xFE
    #define LEVEL_MIN                 0x0
    #define GAMMA_VALUE               2
    #define PWM_FULL_DUTY_CYCLE       1000
    #elif (defined HAL_PWM)
    #define LEVEL_MAX                 0xFE
    #define LEVEL_MIN                 0x0
    #define GAMMA_VALUE               2
    #define PWM_FULL_DUTY_CYCLE       100
    #endif
    
    /*********************************************************************
     * TYPEDEFS
     */
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    byte zclMultiSensor_TaskID;
    uint8 zclMultiSensorSeqNum;
    
    
    /*********************************************************************
     * GLOBAL FUNCTIONS
     */
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    uint8 temp; //mine
    uint16 adc_value;//mine
    
    uint8 Mv_Cnt;//mine
    bool PIR_flag = TRUE;//mine
    uint8 zclOccupancySensor_LastOccupancy = 0x00;//mine
    
    afAddrType_t zclLight1_DstAddr;
    afAddrType_t zclLight2_DstAddr;/*mine*/
    afAddrType_t zclLightSensor_DstAddr;/*mine*/
    afAddrType_t zclOccupancySensor_DstAddr;/*mine*/
    
    aps_Group_t light_group1; /*mine*/
    aps_Group_t light_group2; /*mine*/
    
    //!!!
    
    #ifdef ZCL_EZMODE
    static void zclLight1_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg );
    static void zclLight1_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData );
    
    
    // register EZ-Mode with task information (timeout events, callback, etc...)
    static const zclEZMode_RegisterData_t zclLight1_RegisterEZModeData =
    {
      &zclMultiSensor_TaskID,
      LIGHT_EZMODE_NEXTSTATE_EVT,
      LIGHT_EZMODE_TIMEOUT_EVT,
      &zclMultiSensorSeqNum,
      zclLight1_EZModeCB
    };
    
    #else
    uint16 bindingInClusters[] =
    {
      ZCL_CLUSTER_ID_GEN_ON_OFF
    #ifdef ZCL_LEVEL_CTRL
      , ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL
    #endif
    };
    #define zclLight1_BINDINGLIST (sizeof(bindingInClusters) / sizeof(bindingInClusters[0]))
    
    #endif  // ZCL_EZMODE
    
    // Test Endpoint to allow SYS_APP_MSGs
    static endPointDesc_t LIGHT_TestEp =
    {
      LIGHT1_ENDPOINT,
      &zclMultiSensor_TaskID,
      (SimpleDescriptionFormat_t *)NULL,  // No Simple description for this test endpoint
      (afNetworkLatencyReq_t)0            // No Network Latency req
    };
    
    uint8 giLightScreenMode = LIGHT_MAINMODE;   // display the main screen mode first
    
    uint8 gPermitDuration = 0;    // permit joining default to disabled
    
    devStates_t zclLight1_NwkState = DEV_INIT;
    
    #if ZCL_LEVEL_CTRL
    uint8 zclLight1_WithOnOff;       // set to TRUE if state machine should set light on/off
    uint8 zclLight1_NewLevel;        // new level when done moving
    bool  zclLight1_NewLevelUp;      // is direction to new level up or down?
    int32 zclLight1_CurrentLevel32;  // current level, fixed point (e.g. 192.456)
    int32 zclLight1_Rate32;          // rate in units, fixed point (e.g. 16.123)
    uint8 zclLight1_LevelLastLevel;  // to save the Current Level before the light was turned OFF
    #endif
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    static void zclLight_HandleKeys( byte shift, byte keys );
    static void zclMultiSensor_ReadSensors(void);//mine
    static void zclLightSensor_SendIlluminance( void );//mine
    static void zclMultiSensor_CheckPIR(void);//mine
    static void zclMultiSensor_PIR_SenseMv(void);//mine
    static void zclOccupancySensor_SendOccupancy(void);//mine
    
    
    static void zclLight1_BasicResetCB( void );
    static void zclLight1_IdentifyCB( zclIdentify_t *pCmd );
    static void zclLight1_IdentifyQueryRspCB( zclIdentifyQueryRsp_t *pRsp );
    static void zclLight1_OnOffCB( uint8 cmd );
    static void zclLight1_ProcessIdentifyTimeChange( void );
    /*mine*/
    //static void zclLight2_BasicResetCB( void );
    //static void zclLight2_IdentifyCB( zclIdentify_t *pCmd );
    //static void zclLight2_IdentifyQueryRspCB( zclIdentifyQueryRsp_t *pRsp );
    static void zclLight2_OnOffCB( uint8 cmd );
    //static void zclLight2_ProcessIdentifyTimeChange( void );
    
    #ifdef ZCL_LEVEL_CTRL
    static void zclLight1_LevelControlMoveToLevelCB( zclLCMoveToLevel_t *pCmd );
    static void zclLight1_LevelControlMoveCB( zclLCMove_t *pCmd );
    static void zclLight1_LevelControlStepCB( zclLCStep_t *pCmd );
    static void zclLight1_LevelControlStopCB( void );
    static void zclLight1_DefaultMove( void );
    static uint32 zclLight1_TimeRateHelper( uint8 newLevel );
    static uint16 zclLight1_GetTime ( uint8 level, uint16 time );
    static void zclLight1_MoveBasedOnRate( uint8 newLevel, uint32 rate );
    static void zclLight1_MoveBasedOnTime( uint8 newLevel, uint16 time );
    static void zclLight1_AdjustLightLevel( void );
    
    static void zclLight2_LevelControlMoveToLevelCB( zclLCMoveToLevel_t *pCmd );
    static void zclLight2_LevelControlMoveCB( zclLCMove_t *pCmd );
    static void zclLight2_LevelControlStepCB( zclLCStep_t *pCmd );
    static void zclLight2_LevelControlStopCB( void );
    static void zclLight2_DefaultMove( void );
    static uint32 zclLight2_TimeRateHelper( uint8 newLevel );
    static uint16 zclLight2_GetTime ( uint8 level, uint16 time );
    static void zclLight2_MoveBasedOnRate( uint8 newLevel, uint32 rate );
    static void zclLight2_MoveBasedOnTime( uint8 newLevel, uint16 time );
    static void zclLight2_AdjustLightLevel( void );
    #endif
    
    // app display functions
    static void zclLight1_LcdDisplayUpdate( void );
    #ifdef LCD_SUPPORTED
    static void zclLight1_LcdDisplayMainMode( void );
    static void zclLight1_LcdDisplayHelpMode( void );
    #endif
    static void zclLight_DisplayLight( void );
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    void zclLight1_UpdateLampLevel( uint8 level );
    #endif
    
    // Functions to process ZCL Foundation incoming Command/Response messages
    static void zclLight1_ProcessIncomingMsg( zclIncomingMsg_t *msg );
    #ifdef ZCL_READ
    static uint8 zclLight1_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclLight1_ProcessInReadCmd( zclIncomingMsg_t *pInMsg );//mine
    #endif
    #ifdef ZCL_WRITE
    static uint8 zclLight1_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    static uint8 zclLight1_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg );
    #ifdef ZCL_DISCOVER
    static uint8 zclLight1_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclLight1_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclLight1_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    
    /*********************************************************************
     * STATUS STRINGS
     */
    #ifdef LCD_SUPPORTED
    const char sDeviceName[]   = "  Sample Light";
    const char sClearLine[]    = " ";
    const char sSwLight[]      = "SW1: ToggleLight";  // 16 chars max
    const char sSwEZMode[]     = "SW2: EZ-Mode";
    char sSwHelp[]             = "SW5: Help       ";  // last character is * if NWK open
    const char sLightOn[]      = "    LIGHT ON ";
    const char sLightOff[]     = "    LIGHT OFF";
     #if ZCL_LEVEL_CTRL
     char sLightLevel[]        = "    LEVEL ###"; // displays level 1-254
     #endif
    #endif
    
    /*********************************************************************
     * ZCL General Profile Callback table
     */
    static zclGeneral_AppCallbacks_t zclLight1_CmdCallbacks =
    {
      zclLight1_BasicResetCB,            // Basic Cluster Reset command
      zclLight1_IdentifyCB,              // Identify command
    #ifdef ZCL_EZMODE
      NULL,                                   // Identify EZ-Mode Invoke command
      NULL,                                   // Identify Update Commission State command
    #endif
      NULL,                                   // Identify Trigger Effect command
      zclLight1_IdentifyQueryRspCB,      // Identify Query Response command
      zclLight1_OnOffCB,                 // On/Off cluster commands
      NULL,                                   // On/Off cluster enhanced command Off with Effect
      NULL,                                   // On/Off cluster enhanced command On with Recall Global Scene
      NULL,                                   // On/Off cluster enhanced command On with Timed Off
    #ifdef ZCL_LEVEL_CTRL
      zclLight1_LevelControlMoveToLevelCB, // Level Control Move to Level command
      zclLight1_LevelControlMoveCB,        // Level Control Move command
      zclLight1_LevelControlStepCB,        // Level Control Step command
      zclLight1_LevelControlStopCB,        // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPS
      NULL,                                   // Group Response commands
    #endif
    #ifdef ZCL_SCENES
      NULL,                                  // Scene Store Request command
      NULL,                                  // Scene Recall Request command
      NULL,                                  // Scene Response command
    #endif
    #ifdef ZCL_ALARMS
      NULL,                                  // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXT
      NULL,                                  // Get Event Log command
      NULL,                                  // Publish Event Log command
    #endif
      NULL,                                  // RSSI Location command
      NULL                                   // RSSI Location Response command
    };
    
    
    /*mine*/
    static zclGeneral_AppCallbacks_t zclLight2_CmdCallbacks =
    {
      zclLight1_BasicResetCB,            // Basic Cluster Reset command
      zclLight1_IdentifyCB,              // Identify command
    #ifdef ZCL_EZMODE
      NULL,                                   // Identify EZ-Mode Invoke command
      NULL,                                   // Identify Update Commission State command
    #endif
      NULL,                                   // Identify Trigger Effect command
      zclLight1_IdentifyQueryRspCB,      // Identify Query Response command
      NULL,                 // On/Off cluster commands
      NULL,                                   // On/Off cluster enhanced command Off with Effect
      NULL,                                   // On/Off cluster enhanced command On with Recall Global Scene
      NULL,                                   // On/Off cluster enhanced command On with Timed Off
    #ifdef ZCL_LEVEL_CTRL
      zclLight1_LevelControlMoveToLevelCB, // Level Control Move to Level command
      zclLight1_LevelControlMoveCB,        // Level Control Move command
      zclLight1_LevelControlStepCB,        // Level Control Step command
      zclLight1_LevelControlStopCB,        // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPS
      NULL,                                   // Group Response commands
    #endif
    #ifdef ZCL_SCENES
      NULL,                                  // Scene Store Request command
      NULL,                                  // Scene Recall Request command
      NULL,                                  // Scene Response command
    #endif
    #ifdef ZCL_ALARMS
      NULL,                                  // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXT
      NULL,                                  // Get Event Log command
      NULL,                                  // Publish Event Log command
    #endif
      NULL,                                  // RSSI Location command
      NULL                                   // RSSI Location Response command
    };
    /*end of mine */
    
    /*********************************************************************
     * @fn          zclLight_Init
     *
     * @brief       Initialization function for the zclGeneral layer.
     *
     * @param       none
     *
     * @return      none
     */
    void zclMultiSensor_Init( byte task_id )
    {
      zclMultiSensor_TaskID = task_id;
    
      // Set destination address to indirect
      zclLight1_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
      zclLight1_DstAddr.endPoint = 0;
      zclLight1_DstAddr.addr.shortAddr = 0;
      /*******************************/
      /*mine*/
      zclLight2_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
      zclLight2_DstAddr.endPoint = 0;
      zclLight2_DstAddr.addr.shortAddr = 0;
    
      zclLightSensor_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
      zclLightSensor_DstAddr.endPoint = 8;
      zclLightSensor_DstAddr.addr.shortAddr = 0;
      
      zclOccupancySensor_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
      zclOccupancySensor_DstAddr.endPoint = 8;
      zclOccupancySensor_DstAddr.addr.shortAddr = 0;
      
      /*******************************/
      
      // This app is part of the Home Automation Profile
      zclHA_Init( &zclLight1_SimpleDesc );
      zclHA_Init( &zclLight2_SimpleDesc );/*mine*/ 
      zclHA_Init( &zclLightSensor_SimpleDesc );/*mine*/ 
      zclHA_Init( &zclOccupancySensor_SimpleDesc );/*mine*/ 
      
      // Register the ZCL General Cluster Library callback functions
      zclGeneral_RegisterCmdCallbacks( LIGHT1_ENDPOINT, &zclLight1_CmdCallbacks );
      zclGeneral_RegisterCmdCallbacks( LIGHT2_ENDPOINT, &zclLight2_CmdCallbacks );/*mine*/ 
    
      // Register the application's attribute list
      zcl_registerAttrList( LIGHT1_ENDPOINT, zclLight1_NumAttributes, zclLight1_Attrs );
      zcl_registerAttrList( LIGHT2_ENDPOINT, zclLight2_NumAttributes, zclLight2_Attrs );/*mine*/ 
      zcl_registerAttrList( OCCUPANCYSENSOR_ENDPOINT, zclLight2_NumAttributes, zclLightSensor_Attrs );/*mine*/ 
      zcl_registerAttrList( LIGHTSENSOR_ENDPOINT, zclLight2_NumAttributes, zclOccupancySensor_Attrs );/*mine*/ 
      
      // Register the Application to receive the unprocessed Foundation command/response messages
      zcl_registerForMsg( zclMultiSensor_TaskID );
    
    #ifdef ZCL_DISCOVER
      // Register the application's command list
      zcl_registerCmdList( LIGHT1_ENDPOINT, zclLight1CmdsArraySize, zclLight1_Cmds );
      zcl_registerCmdList( LIGHT2_ENDPOINT, zclLight2CmdsArraySize, zclLight2_Cmds );
      zcl_registerCmdList( OCCUPANCYSENSOR_ENDPOINT, zclOccupancySensorCmdsArraySize, zclOccupancySensor_Cmds );
      zcl_registerCmdList( LIGHTSENSOR_ENDPOINT, zclLightSensorCmdsArraySize, zclLightSensor_Cmds );
    #endif
    
      // Register for all key events - This app will handle all key events
      RegisterForKeys( zclMultiSensor_TaskID );
    
      // Register for a test endpoint
      afRegister( &LIGHT_TestEp );
    
    #ifdef ZCL_EZMODE
      // Register EZ-Mode
      zcl_RegisterEZMode( &zclLight1_RegisterEZModeData );
    
      // Register with the ZDO to receive Match Descriptor Responses
      ZDO_RegisterForZDOMsg(task_id, Match_Desc_rsp);
    #endif
    
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
      HalTimer1Init( 0 );
      halTimer1SetChannelDuty( WHITE_LED, 0 );
      halTimer1SetChannelDuty( RED_LED, 0 );
      halTimer1SetChannelDuty( BLUE_LED, 0 );
      halTimer1SetChannelDuty( GREEN_LED, 0 );
    
      // find if we are already on a network from NV_RESTORE
      uint8 state;
      NLME_GetRequest( nwkNwkState, 0, &state );
    
      if ( state < NWK_ENDDEVICE )
      {
        // Start EZMode on Start up to avoid button press
        osal_start_timerEx( zclMultiSensor_TaskID, LIGHT_START_EZMODE_EVT, 500 );
      }
    #if ZCL_LEVEL_CTRL
      zclLight1_DefaultMove();
    #endif
    #endif // #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    
    #ifdef ZCL_DIAGNOSTIC
      // Register the application's callback function to read/write attribute data.
      // This is only required when the attribute data format is unknown to ZCL.
      zcl_registerReadWriteCB( LIGHT1_ENDPOINT, zclDiagnostic_ReadWriteAttrCB, NULL );
    
      if ( zclDiagnostic_InitStats() == ZSuccess )
      {
        // Here the user could start the timer to save Diagnostics to NV
      }
    #endif
    
    #ifdef LCD_SUPPORTED
      HalLcdWriteString ( (char *)sDeviceName, HAL_LCD_LINE_3 );
    #endif  // LCD_SUPPORTED
    
    #ifdef ZGP_AUTO_TT
      zgpTranslationTable_RegisterEP ( &zclLight1_SimpleDesc );
    #endif
      
      /*****************mine****************/
      /***************group membership********/
      /**************just for test***********/
      light_group1.ID =0;
      light_group1.name[1] = 'R';
      light_group1.name[2] = 'e';
      light_group1.name[3] = 'l';
      light_group1.name[4] = 'a';
      light_group1.name[5] = 'y';
      light_group1.name[6] = '1';
      aps_AddGroup( LIGHT1_ENDPOINT, &light_group1 );
      
      light_group2.ID =1;
      light_group2.name[1] = 'R';
      light_group2.name[2] = 'e';
      light_group2.name[3] = 'l';
      light_group2.name[4] = 'a';
      light_group2.name[5] = 'y';
      light_group2.name[6] = '2';
      aps_AddGroup( LIGHT2_ENDPOINT, &light_group2 );
      /****************************************/
      
        //mine
      
      // start a reload timer.On timer OVF we check ADC for measuring Battery Voltage
      temp = osal_start_reload_timer( zclMultiSensor_TaskID,LIGHT_ADC_TIMER_EVT,5000); 
      if(temp==SUCCESS)
      {
        // write something on serial port
      }
      else
      {
        // write something on serial port    
      }
      
      //end of mine
      
    }
    
    /*********************************************************************
     * @fn          zclSample_event_loop
     *
     * @brief       Event Loop Processor for zclGeneral.
     *
     * @param       none
     *
     * @return      none
     */
    uint16 zclMultiSensor_event_loop( uint8 task_id, uint16 events )
    {
      afIncomingMSGPacket_t *MSGpkt;
    
      (void)task_id;  // Intentionally unreferenced parameter
    
      if ( events & SYS_EVENT_MSG )
      {
        while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( zclMultiSensor_TaskID )) )
        {
          switch ( MSGpkt->hdr.event )
          {
    #ifdef ZCL_EZMODE
            case ZDO_CB_MSG:
              zclLight1_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
              break;
    #endif
            case ZCL_INCOMING_MSG:
              // Incoming ZCL Foundation command/response messages
              zclLight1_ProcessIncomingMsg( (zclIncomingMsg_t *)MSGpkt );
              break;
    
            case KEY_CHANGE:
              zclLight_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
              break;
    
            case ZDO_STATE_CHANGE:
              zclLight1_NwkState = (devStates_t)(MSGpkt->hdr.status);
    
              // now on the network
              if ( (zclLight1_NwkState == DEV_ZB_COORD) ||
                   (zclLight1_NwkState == DEV_ROUTER)   ||
                   (zclLight1_NwkState == DEV_END_DEVICE) )
              {
                giLightScreenMode = LIGHT_MAINMODE;
                zclLight1_LcdDisplayUpdate();
    #ifdef ZCL_EZMODE
                zcl_EZModeAction( EZMODE_ACTION_NETWORK_STARTED, NULL );
    #endif // ZCL_EZMODE
              }
              break;
    
            default:
              break;
          }
    
          // Release the memory
          osal_msg_deallocate( (uint8 *)MSGpkt );
        }
    
        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
      }
    
      if ( events & LIGHT_IDENTIFY_TIMEOUT_EVT )
      {
        if ( zclLight1_IdentifyTime > 0 )
          zclLight1_IdentifyTime--;
        zclLight1_ProcessIdentifyTimeChange();
    
        return ( events ^ LIGHT_IDENTIFY_TIMEOUT_EVT );
      }
    
      if ( events & LIGHT_MAIN_SCREEN_EVT )
      {
        giLightScreenMode = LIGHT_MAINMODE;
        zclLight1_LcdDisplayUpdate();
    
        return ( events ^ LIGHT_MAIN_SCREEN_EVT );
      }
    
    #ifdef ZCL_EZMODE
    #if (defined HAL_BOARD_ZLIGHT)
      // event to start EZMode on startup with a delay
      if ( events & LIGHT_START_EZMODE_EVT )
      {
        // Invoke EZ-Mode
        zclEZMode_InvokeData_t ezModeData;
    
        // Invoke EZ-Mode
        ezModeData.endpoint = LIGHT1_ENDPOINT; // endpoint on which to invoke EZ-Mode
        if ( (zclLight1_NwkState == DEV_ZB_COORD) ||
             (zclLight1_NwkState == DEV_ROUTER)   ||
             (zclLight1_NwkState == DEV_END_DEVICE) )
        {
          ezModeData.onNetwork = TRUE;      // node is already on the network
        }
        else
        {
          ezModeData.onNetwork = FALSE;     // node is not yet on the network
        }
        ezModeData.initiator = FALSE;          // OnOffLight is a target
        ezModeData.numActiveOutClusters = 0;
        ezModeData.pActiveOutClusterIDs = NULL;
        ezModeData.numActiveInClusters = 0;
        ezModeData.pActiveOutClusterIDs = NULL;
        zcl_InvokeEZMode( &ezModeData );
    
        return ( events ^ LIGHT_START_EZMODE_EVT );
      }
    #endif // #if (defined HAL_BOARD_ZLIGHT)
    
      // going on to next state
      if ( events & LIGHT_EZMODE_NEXTSTATE_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_PROCESS, NULL );   // going on to next state
        return ( events ^ LIGHT_EZMODE_NEXTSTATE_EVT );
      }
    
      // the overall EZMode timer expired, so we timed out
      if ( events & LIGHT_EZMODE_TIMEOUT_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_TIMED_OUT, NULL ); // EZ-Mode timed out
        return ( events ^ LIGHT_EZMODE_TIMEOUT_EVT );
      }
    #endif // ZLC_EZMODE
    
    #ifdef ZCL_LEVEL_CTRL
      if ( events & LIGHT_LEVEL_CTRL_EVT )
      {
        zclLight1_AdjustLightLevel();
        return ( events ^ LIGHT_LEVEL_CTRL_EVT );
      }
    #endif
      
      /***********************mine***********************************/  
      
      if ( events & LIGHT_ADC_TIMER_EVT )
      {
        zclMultiSensor_ReadSensors(); 
        return ( events ^ LIGHT_ADC_TIMER_EVT );
      }
      
      
      if ( events & zclOccupancySensor_UtoO_TIMER_EVT )
      {
        zclMultiSensor_CheckPIR(); 
        return ( events ^ zclOccupancySensor_UtoO_TIMER_EVT );
      }
        
    
      if ( events & zclOccupancySensor_OtoU_TIMER_EVT )
      {
        zclMultiSensor_CheckPIR();    
        return ( events ^ zclOccupancySensor_OtoU_TIMER_EVT );
      }  
    
      // Discard unknown events
      return 0;
    }
    
    /*********************************************************************
     * @fn      zclLight_HandleKeys
     *
     * @brief   Handles all key events for this device.
     *
     * @param   shift - true if in shift/alt.
     * @param   keys - bit field for key events. Valid entries:
     *                 HAL_KEY_SW_5
     *                 HAL_KEY_SW_4
     *                 HAL_KEY_SW_2
     *                 HAL_KEY_SW_1
     *
     * @return  none
     */
    static void zclLight_HandleKeys( byte shift, byte keys )
    {
      if ( keys & HAL_KEY_SW_1 )
      {
        giLightScreenMode = LIGHT_MAINMODE;
         zclMultiSensor_PIR_SenseMv();
        // toggle local light immediately
       // zclLight1_OnOff = zclLight1_OnOff ? LIGHT_OFF : LIGHT_ON;
    #ifdef ZCL_LEVEL_CTRL
        zclLight1_LevelCurrentLevel = zclLight1_OnOff ? zclLight1_LevelOnLevel : ATTR_LEVEL_MIN_LEVEL;
    #endif
      }
    
      if ( keys & HAL_KEY_SW_2 )
      {
    #if (defined HAL_BOARD_ZLIGHT)
    
        zclLight1_BasicResetCB();
    
    #else
    
        giLightScreenMode = LIGHT_MAINMODE;
    
    #ifdef ZCL_EZMODE
        {
          // Invoke EZ-Mode
          zclEZMode_InvokeData_t ezModeData;
    
          // Invoke EZ-Mode
          ezModeData.endpoint = LIGHT1_ENDPOINT; // endpoint on which to invoke EZ-Mode
          if ( (zclLight1_NwkState == DEV_ZB_COORD) ||
              (zclLight1_NwkState == DEV_ROUTER)   ||
                (zclLight1_NwkState == DEV_END_DEVICE) )
          {
            ezModeData.onNetwork = TRUE;      // node is already on the network
          }
          else
          {
            ezModeData.onNetwork = FALSE;     // node is not yet on the network
          }
          ezModeData.initiator = FALSE;          // OnOffLight is a target
          ezModeData.numActiveOutClusters = 0;
          ezModeData.pActiveOutClusterIDs = NULL;
          ezModeData.numActiveInClusters = 0;
          ezModeData.pActiveOutClusterIDs = NULL;
          zcl_InvokeEZMode( &ezModeData );
        }
    
    #else // NOT EZ-Mode
        {
          zAddrType_t dstAddr;
          HalLedSet ( HAL_LED_Identify, HAL_LED_MODE_OFF );
    
          // Initiate an End Device Bind Request, this bind request will
          // only use a cluster list that is important to binding.
          dstAddr.addrMode = afAddr16Bit;
          dstAddr.addr.shortAddr = 0;   // Coordinator makes the match
          ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
                               LIGHT1_ENDPOINT,
                               ZCL_HA_PROFILE_ID,
                               zclLight1_BINDINGLIST, bindingInClusters,
                               0, NULL,   // No Outgoing clusters to bind
                               TRUE );
        }
    #endif // ZCL_EZMODE
    #endif // HAL_BOARD_ZLIGHT
      }
    
      if ( keys & HAL_KEY_SW_3 )
      {
        NLME_SendNetworkStatus( zclLight1_DstAddr.addr.shortAddr,
                           NLME_GetShortAddr(), NWKSTAT_NONTREE_LINK_FAILURE, FALSE );
      }
    
      if ( keys & HAL_KEY_SW_4 )
      {
        giLightScreenMode = LIGHT_MAINMODE;
    
        if ( ( zclLight1_NwkState == DEV_ZB_COORD ) ||
              ( zclLight1_NwkState == DEV_ROUTER ) )
        {
          zAddrType_t tmpAddr;
    
          tmpAddr.addrMode = Addr16Bit;
          tmpAddr.addr.shortAddr = NLME_GetShortAddr();
    
          // toggle permit join
          gPermitDuration = gPermitDuration ? 0 : 0xff;
    
          // Trust Center significance is always true
          ZDP_MgmtPermitJoinReq( &tmpAddr, gPermitDuration, TRUE, FALSE );
        }
      }
    
      // Shift F5 does a Basic Reset (factory defaults)
      if ( shift && ( keys & HAL_KEY_SW_5 ) )
      {
        zclLight1_BasicResetCB();
      }
      else if ( keys & HAL_KEY_SW_5 )
      {
        giLightScreenMode = giLightScreenMode ? LIGHT_MAINMODE : LIGHT_HELPMODE;
        /******mine******/
        zclLight2_OnOff = zclLight2_OnOff ? LIGHT_OFF : LIGHT_ON; //mine
        /****************/
      }
    
      // update the display, including the light
      zclLight1_LcdDisplayUpdate();
    }
    
    /*********************************************************************
     * @fn      zclLight1_LcdDisplayUpdate
     *
     * @brief   Called to update the LCD display.
     *
     * @param   none
     *
     * @return  none
     */
    void zclLight1_LcdDisplayUpdate( void )
    {
    #ifdef LCD_SUPPORTED
      if ( giLightScreenMode == LIGHT_HELPMODE )
      {
        zclLight1_LcdDisplayHelpMode();
      }
      else
      {
        zclLight1_LcdDisplayMainMode();
      }
    #endif
    
      zclLight_DisplayLight();
    }
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    /*********************************************************************
     * @fn      zclLight1_UpdateLampLevel
     *
     * @brief   Update lamp level output with gamma compensation
     *
     * @param   level
     *
     * @return  none
     */
    void zclLight1_UpdateLampLevel( uint8 level )
    
    {
      uint16 gammaCorrectedLevel;
    
      // gamma correct the level
      gammaCorrectedLevel = (uint16) ( pow( ( (float)level / LEVEL_MAX ), (float)GAMMA_VALUE ) * (float)LEVEL_MAX);
    
      halTimer1SetChannelDuty(WHITE_LED, (uint16)(((uint32)gammaCorrectedLevel*PWM_FULL_DUTY_CYCLE)/LEVEL_MAX) );
    }
    #endif
    
    /*********************************************************************
     * @fn      zclLight_DisplayLight
     *
     * @brief   Displays current state of light on LED and also on main display if supported.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight_DisplayLight( void )
    {
      // set the RELAY1 based on light (on or off)
      if ( zclLight1_OnOff == LIGHT_ON )
      {
        HalLedSet ( HAL_LED_Identify, HAL_LED_MODE_ON );
      }
      else
      {
        HalLedSet ( HAL_LED_Identify, HAL_LED_MODE_OFF );
      }
      
      /****************mine********************/
      // set the RELAY2 based on light (on or off)
      if ( zclLight2_OnOff == LIGHT_ON )
      {
        HalLedSet ( HAL_RELAY_2, HAL_LED_MODE_ON );
      }
      else
      {
        HalLedSet ( HAL_RELAY_2, HAL_LED_MODE_OFF );
      }  
      /****************************************/
    
    #ifdef LCD_SUPPORTED
      if (giLightScreenMode == LIGHT_MAINMODE)
      {
    #ifdef ZCL_LEVEL_CTRL
        // display current light level
        if ( ( zclLight1_LevelCurrentLevel == ATTR_LEVEL_MIN_LEVEL ) &&
             ( zclLight1_OnOff == LIGHT_OFF ) )
        {
          HalLcdWriteString( (char *)sLightOff, HAL_LCD_LINE_2 );
        }
        else if ( ( zclLight1_LevelCurrentLevel >= ATTR_LEVEL_MAX_LEVEL ) ||
                  ( zclLight1_LevelCurrentLevel == zclLight1_LevelOnLevel ) ||
                   ( ( zclLight1_LevelOnLevel == ATTR_LEVEL_ON_LEVEL_NO_EFFECT ) &&
                     ( zclLight1_LevelCurrentLevel == zclLight1_LevelLastLevel ) ) )
        {
          HalLcdWriteString( (char *)sLightOn, HAL_LCD_LINE_2 );
        }
        else    // "    LEVEL ###"
        {
          zclHA_uint8toa( zclLight1_LevelCurrentLevel, &sLightLevel[10] );
          HalLcdWriteString( (char *)sLightLevel, HAL_LCD_LINE_2 );
        }
    #else
        if ( zclLight1_OnOff )
        {
          HalLcdWriteString( (char *)sLightOn, HAL_LCD_LINE_2 );
        }
        else
        {
          HalLcdWriteString( (char *)sLightOff, HAL_LCD_LINE_2 );
        }
    #endif // ZCL_LEVEL_CTRL
      }
    #endif // LCD_SUPPORTED
    }
    
    #ifdef LCD_SUPPORTED
    /*********************************************************************
     * @fn      zclLight1_LcdDisplayMainMode
     *
     * @brief   Called to display the main screen on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight1_LcdDisplayMainMode( void )
    {
      // display line 1 to indicate NWK status
      if ( zclLight1_NwkState == DEV_ZB_COORD )
      {
        zclHA_LcdStatusLine1( ZCL_HA_STATUSLINE_ZC );
      }
      else if ( zclLight1_NwkState == DEV_ROUTER )
      {
        zclHA_LcdStatusLine1( ZCL_HA_STATUSLINE_ZR );
      }
      else if ( zclLight1_NwkState == DEV_END_DEVICE )
      {
        zclHA_LcdStatusLine1( ZCL_HA_STATUSLINE_ZED );
      }
    
      // end of line 3 displays permit join status (*)
      if ( gPermitDuration )
      {
        sSwHelp[15] = '*';
      }
      else
      {
        sSwHelp[15] = ' ';
      }
      HalLcdWriteString( (char *)sSwHelp, HAL_LCD_LINE_3 );
    }
    
    /*********************************************************************
     * @fn      zclLight1_LcdDisplayHelpMode
     *
     * @brief   Called to display the SW options on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight1_LcdDisplayHelpMode( void )
    {
      HalLcdWriteString( (char *)sSwLight, HAL_LCD_LINE_1 );
      HalLcdWriteString( (char *)sSwEZMode, HAL_LCD_LINE_2 );
      HalLcdWriteString( (char *)sSwHelp, HAL_LCD_LINE_3 );
    }
    #endif  // LCD_SUPPORTED
    
    /*********************************************************************
     * @fn      zclLight1_ProcessIdentifyTimeChange
     *
     * @brief   Called to process any change to the IdentifyTime attribute.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight1_ProcessIdentifyTimeChange( void )
    {
      if ( zclLight1_IdentifyTime > 0 )
      {
        osal_start_timerEx( zclMultiSensor_TaskID, LIGHT_IDENTIFY_TIMEOUT_EVT, 1000 );
        HalLedBlink ( HAL_LED_Identify, 0xFF, HAL_LED_DEFAULT_DUTY_CYCLE, HAL_LED_DEFAULT_FLASH_TIME );
      }
      else
      {
    #ifdef ZCL_EZMODE
        if ( zclLight1_IdentifyCommissionState & EZMODE_COMMISSION_OPERATIONAL )
        {
          HalLedSet ( HAL_LED_Identify, HAL_LED_MODE_ON );
        }
        else
        {
          HalLedSet ( HAL_LED_Identify, HAL_LED_MODE_OFF );
        }
    #endif
    
        osal_stop_timerEx( zclMultiSensor_TaskID, LIGHT_IDENTIFY_TIMEOUT_EVT );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight1_BasicResetCB
     *
     * @brief   Callback from the ZCL General Cluster Library
     *          to set all the Basic Cluster attributes to default values.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight1_BasicResetCB( void )
    {
      NLME_LeaveReq_t leaveReq;
      // Set every field to 0
      osal_memset( &leaveReq, 0, sizeof( NLME_LeaveReq_t ) );
    
      // This will enable the device to rejoin the network after reset.
      leaveReq.rejoin = TRUE;
    
      // Set the NV startup option to force a "new" join.
      zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );
    
      // Leave the network, and reset afterwards
      if ( NLME_LeaveReq( &leaveReq ) != ZSuccess )
      {
        // Couldn't send out leave; prepare to reset anyway
        ZDApp_LeaveReset( FALSE );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight1_IdentifyCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Command for this application.
     *
     * @param   srcAddr - source address and endpoint of the response message
     * @param   identifyTime - the number of seconds to identify yourself
     *
     * @return  none
     */
    static void zclLight1_IdentifyCB( zclIdentify_t *pCmd )
    {
      zclLight1_IdentifyTime = pCmd->identifyTime;
      zclLight1_ProcessIdentifyTimeChange();
    }
    
    /*********************************************************************
     * @fn      zclLight1_IdentifyQueryRspCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Query Response Command for this application.
     *
     * @param   srcAddr - requestor's address
     * @param   timeout - number of seconds to identify yourself (valid for query response)
     *
     * @return  none
     */
    static void zclLight1_IdentifyQueryRspCB(  zclIdentifyQueryRsp_t *pRsp )
    {
      (void)pRsp;
    #ifdef ZCL_EZMODE
      {
        zclEZMode_ActionData_t data;
        data.pIdentifyQueryRsp = pRsp;
        zcl_EZModeAction ( EZMODE_ACTION_IDENTIFY_QUERY_RSP, &data );
      }
    #endif
    }
    
    /*********************************************************************
     * @fn      zclLight1_OnOffCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an On/Off Command for this application.
     *
     * @param   cmd - COMMAND_ON, COMMAND_OFF or COMMAND_TOGGLE
     *
     * @return  none
     */
    static void zclLight1_OnOffCB( uint8 cmd )
    {
      afIncomingMSGPacket_t *pPtr = zcl_getRawAFMsg();
    
      zclLight1_DstAddr.addr.shortAddr = pPtr->srcAddr.addr.shortAddr;
    
    
      // Turn on the light
      if ( cmd == COMMAND_ON )
      {
        zclLight1_OnOff = LIGHT_ON;
      }
      // Turn off the light
      else if ( cmd == COMMAND_OFF )
      {
        zclLight1_OnOff = LIGHT_OFF;
      }
      // Toggle the light
      else if ( cmd == COMMAND_TOGGLE )
      {
        if ( zclLight1_OnOff == LIGHT_OFF )
        {
          zclLight1_OnOff = LIGHT_ON;
        }
        else
        {
          zclLight1_OnOff = LIGHT_OFF;
        }
      }
    
    #if ZCL_LEVEL_CTRL
      zclLight1_DefaultMove( );
    #endif
    
      // update the display
      zclLight1_LcdDisplayUpdate( );
    }
    
    /***************************mine**********************************
     * @fn      zclLight2_OnOffCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an On/Off Command for this application.
     *
     * @param   cmd - COMMAND_ON, COMMAND_OFF or COMMAND_TOGGLE
     *
     * @return  none
     */
    static void zclLight2_OnOffCB( uint8 cmd )
    {
      afIncomingMSGPacket_t *pPtr = zcl_getRawAFMsg();
    
      zclLight1_DstAddr.addr.shortAddr = pPtr->srcAddr.addr.shortAddr;
    
    
      // Turn on the light
      if ( cmd == COMMAND_ON )
      {
        zclLight2_OnOff = LIGHT_ON;
      }
      // Turn off the light
      else if ( cmd == COMMAND_OFF )
      {
        zclLight2_OnOff = LIGHT_OFF;
      }
      // Toggle the light
      else if ( cmd == COMMAND_TOGGLE )
      {
        if ( zclLight2_OnOff == LIGHT_OFF )
        {
          zclLight2_OnOff = LIGHT_ON;
        }
        else
        {
          zclLight2_OnOff = LIGHT_OFF;
        }
      }
    
    #if ZCL_LEVEL_CTRL
      zclLight2_DefaultMove( );
    #endif
    
      // update the display
      zclLight1_LcdDisplayUpdate( );
    }
    
    #ifdef ZCL_LEVEL_CTRL
    /*********************************************************************
     * @fn      zclLight1_TimeRateHelper
     *
     * @brief   Calculate time based on rate, and startup level state machine
     *
     * @param   newLevel - new level for current level
     *
     * @return  diff (directly), zclLight1_CurrentLevel32 and zclLight1_NewLevel, zclLight1_NewLevelUp
     */
    static uint32 zclLight1_TimeRateHelper( uint8 newLevel )
    {
      uint32 diff;
      uint32 newLevel32;
    
      // remember current and new level
      zclLight1_NewLevel = newLevel;
      zclLight1_CurrentLevel32 = (uint32)1000 * zclLight1_LevelCurrentLevel;
    
      // calculate diff
      newLevel32 = (uint32)1000 * newLevel;
      if ( zclLight1_LevelCurrentLevel > newLevel )
      {
        diff = zclLight1_CurrentLevel32 - newLevel32;
        zclLight1_NewLevelUp = FALSE;  // moving down
      }
      else
      {
        diff = newLevel32 - zclLight1_CurrentLevel32;
        zclLight1_NewLevelUp = TRUE;   // moving up
      }
    
      return ( diff );
    }
    
    /*********************************************************************
     * @fn      zclLight1_MoveBasedOnRate
     *
     * @brief   Calculate time based on rate, and startup level state machine
     *
     * @param   newLevel - new level for current level
     * @param   rate16   - fixed point rate (e.g. 16.123)
     *
     * @return  none
     */
    static void zclLight1_MoveBasedOnRate( uint8 newLevel, uint32 rate )
    {
      uint32 diff;
    
      // determine how much time (in 10ths of seconds) based on the difference and rate
      zclLight1_Rate32 = rate;
      diff = zclLight1_TimeRateHelper( newLevel );
      zclLight1_LevelRemainingTime = diff / rate;
      if ( !zclLight1_LevelRemainingTime )
      {
        zclLight1_LevelRemainingTime = 1;
      }
    
      osal_start_timerEx( zclMultiSensor_TaskID, LIGHT_LEVEL_CTRL_EVT, 100 );
    }
    
    /*********************************************************************
     * @fn      zclLight1_MoveBasedOnTime
     *
     * @brief   Calculate rate based on time, and startup level state machine
     *
     * @param   newLevel  - new level for current level
     * @param   time      - in 10ths of seconds
     *
     * @return  none
     */
    static void zclLight1_MoveBasedOnTime( uint8 newLevel, uint16 time )
    {
      uint16 diff;
    
      // determine rate (in units) based on difference and time
      diff = zclLight1_TimeRateHelper( newLevel );
      zclLight1_LevelRemainingTime = zclLight1_GetTime( newLevel, time );
      zclLight1_Rate32 = diff / time;
    
      osal_start_timerEx( zclMultiSensor_TaskID, LIGHT_LEVEL_CTRL_EVT, 100 );
    }
    
    /*********************************************************************
     * @fn      zclLight1_GetTime
     *
     * @brief   Determine amount of time that MoveXXX will take to complete.
     *
     * @param   level = new level to move to
     *          time  = 0xffff=default, or 0x0000-n amount of time in tenths of seconds.
     *
     * @return  none
     */
    static uint16 zclLight1_GetTime( uint8 level, uint16 time )
    {
      // there is a hiearchy of the amount of time to use for transistioning
      // check each one in turn. If none of defaults are set, then use fastest
      // time possible.
      if ( time == 0xFFFF )
      {
        // use On or Off Transition Time if set (not 0xffff)
        if ( zclLight1_OnOff == LIGHT_ON )
        {
          time = zclLight1_LevelOffTransitionTime;
        }
        else
        {
          time = zclLight1_LevelOnTransitionTime;
        }
    
        // else use OnOffTransitionTime if set (not 0xffff)
        if ( time == 0xFFFF )
        {
          time = zclLight1_LevelOnOffTransitionTime;
        }
    
        // else as fast as possible
        if ( time == 0xFFFF )
        {
          time = 1;
        }
      }
    
      if ( !time )
      {
        time = 1; // as fast as possible
      }
    
      return ( time );
    }
    
    /*********************************************************************
     * @fn      zclLight1_DefaultMove
     *
     * @brief   We were turned on/off. Use default time to move to on or off.
     *
     * @param   zclLight1_OnOff - must be set prior to calling this function.
     *
     * @return  none
     */
    static void zclLight1_DefaultMove( void )
    {
      uint8  newLevel;
      uint32 rate;      // fixed point decimal (3 places, eg. 16.345)
      uint16 time;
    
      // if moving to on position, move to on level
      if ( zclLight1_OnOff )
      {
        if ( zclLight1_LevelOnLevel == ATTR_LEVEL_ON_LEVEL_NO_EFFECT )
        {
          // The last Level (before going OFF) should be used)
          newLevel = zclLight1_LevelLastLevel;
        }
        else
        {
          newLevel = zclLight1_LevelOnLevel;
        }
    
        time = zclLight1_LevelOnTransitionTime;
      }
      else
      {
        newLevel = ATTR_LEVEL_MIN_LEVEL;
    
        if ( zclLight1_LevelOnLevel == ATTR_LEVEL_ON_LEVEL_NO_EFFECT )
        {
          // Save the current Level before going OFF to use it when the light turns ON
          // it should be back to this level
          zclLight1_LevelLastLevel = zclLight1_LevelCurrentLevel;
        }
    
        time = zclLight1_LevelOffTransitionTime;
      }
    
      // else use OnOffTransitionTime if set (not 0xffff)
      if ( time == 0xFFFF )
      {
        time = zclLight1_LevelOnOffTransitionTime;
      }
    
      // else as fast as possible
      if ( time == 0xFFFF )
      {
        time = 1;
      }
    
      // calculate rate based on time (int 10ths) for full transition (1-254)
      rate = 255000 / time;    // units per tick, fixed point, 3 decimal places (e.g. 8500 = 8.5 units per tick)
    
      // start up state machine.
      zclLight1_WithOnOff = TRUE;
      zclLight1_MoveBasedOnRate( newLevel, rate );
    }
    
    /*********************************************************************
     * @fn      zclLight1_AdjustLightLevel
     *
     * @brief   Called each 10th of a second while state machine running
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight1_AdjustLightLevel( void )
    {
      // one tick (10th of a second) less
      if ( zclLight1_LevelRemainingTime )
      {
        --zclLight1_LevelRemainingTime;
      }
    
      // no time left, done
      if ( zclLight1_LevelRemainingTime == 0)
      {
        zclLight1_LevelCurrentLevel = zclLight1_NewLevel;
      }
    
      // still time left, keep increment/decrementing
      else
      {
        if ( zclLight1_NewLevelUp )
        {
          zclLight1_CurrentLevel32 += zclLight1_Rate32;
        }
        else
        {
          zclLight1_CurrentLevel32 -= zclLight1_Rate32;
        }
        zclLight1_LevelCurrentLevel = (uint8)( zclLight1_CurrentLevel32 / 1000 );
      }
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
      zclLight1_UpdateLampLevel(zclLight1_LevelCurrentLevel);
    #endif
    
      // also affect on/off
      if ( zclLight1_WithOnOff )
      {
        if ( zclLight1_LevelCurrentLevel > ATTR_LEVEL_MIN_LEVEL )
        {
          zclLight1_OnOff = LIGHT_ON;
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
          ENABLE_LAMP;
    #endif
        }
        else
        {
          zclLight1_OnOff = LIGHT_OFF;
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
          DISABLE_LAMP;
    #endif
        }
      }
    
      // display light level as we go
      zclLight_DisplayLight( );
    
      // keep ticking away
      if ( zclLight1_LevelRemainingTime )
      {
        osal_start_timerEx( zclMultiSensor_TaskID, LIGHT_LEVEL_CTRL_EVT, 100 );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight1_LevelControlMoveToLevelCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received a LevelControlMoveToLevel Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight1_LevelControlMoveToLevelCB( zclLCMoveToLevel_t *pCmd )
    {
      zclLight1_WithOnOff = pCmd->withOnOff;
      zclLight1_MoveBasedOnTime( pCmd->level, pCmd->transitionTime );
    }
    
    /*********************************************************************
     * @fn      zclLight1_LevelControlMoveCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received a LevelControlMove Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight1_LevelControlMoveCB( zclLCMove_t *pCmd )
    {
      uint8 newLevel;
      uint32 rate;
    
      // convert rate from units per second to units per tick (10ths of seconds)
      // and move at that right up or down
      zclLight1_WithOnOff = pCmd->withOnOff;
    
      if ( pCmd->moveMode == LEVEL_MOVE_UP )
      {
        newLevel = ATTR_LEVEL_MAX_LEVEL;  // fully on
      }
      else
      {
        newLevel = ATTR_LEVEL_MIN_LEVEL; // fully off
      }
    
      rate = (uint32)100 * pCmd->rate;
      zclLight1_MoveBasedOnRate( newLevel, rate );
    }
    
    /*********************************************************************
     * @fn      zclLight1_LevelControlStepCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an On/Off Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight1_LevelControlStepCB( zclLCStep_t *pCmd )
    {
      uint8 newLevel;
    
      // determine new level, but don't exceed boundaries
      if ( pCmd->stepMode == LEVEL_MOVE_UP )
      {
        if ( (uint16)zclLight1_LevelCurrentLevel + pCmd->amount > ATTR_LEVEL_MAX_LEVEL )
        {
          newLevel = ATTR_LEVEL_MAX_LEVEL;
        }
        else
        {
          newLevel = zclLight1_LevelCurrentLevel + pCmd->amount;
        }
      }
      else
      {
        if ( pCmd->amount >= zclLight1_LevelCurrentLevel )
        {
          newLevel = ATTR_LEVEL_MIN_LEVEL;
        }
        else
        {
          newLevel = zclLight1_LevelCurrentLevel - pCmd->amount;
        }
      }
    
      // move to the new level
      zclLight1_WithOnOff = pCmd->withOnOff;
      zclLight1_MoveBasedOnTime( newLevel, pCmd->transitionTime );
    }
    
    /*********************************************************************
     * @fn      zclLight1_LevelControlStopCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Level Control Stop Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight1_LevelControlStopCB( void )
    {
      // stop immediately
      osal_stop_timerEx( zclMultiSensor_TaskID, LIGHT_LEVEL_CTRL_EVT );
      zclLight1_LevelRemainingTime = 0;
    }
    #endif
    
    /******************************************************************************
     *
     *  Functions for processing ZCL Foundation incoming Command/Response messages
     *
     *****************************************************************************/
    
    /*********************************************************************
     * @fn      zclLight1_ProcessIncomingMsg
     *
     * @brief   Process ZCL Foundation incoming message
     *
     * @param   pInMsg - pointer to the received message
     *
     * @return  none
     */
    static void zclLight1_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg )
    {
      switch ( pInMsg->zclHdr.commandID )
      {
    #ifdef ZCL_READ
        case ZCL_CMD_READ:
          zclLight1_ProcessInReadCmd(pInMsg);
          break;    
        case ZCL_CMD_READ_RSP:
          zclLight1_ProcessInReadRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_WRITE
        case ZCL_CMD_WRITE_RSP:
          zclLight1_ProcessInWriteRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_REPORT
        // Attribute Reporting implementation should be added here
        case ZCL_CMD_CONFIG_REPORT:
          // zclLight1_ProcessInConfigReportCmd( pInMsg );
          break;
    
        case ZCL_CMD_CONFIG_REPORT_RSP:
          // zclLight1_ProcessInConfigReportRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG:
          // zclLight1_ProcessInReadReportCfgCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG_RSP:
          // zclLight1_ProcessInReadReportCfgRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_REPORT:
          // zclLight1_ProcessInReportCmd( pInMsg );
          break;
    #endif
        case ZCL_CMD_DEFAULT_RSP:
          zclLight1_ProcessInDefaultRspCmd( pInMsg );
          break;
    #ifdef ZCL_DISCOVER
        case ZCL_CMD_DISCOVER_CMDS_RECEIVED_RSP:
          zclLight1_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_CMDS_GEN_RSP:
          zclLight1_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_RSP:
          zclLight1_ProcessInDiscAttrsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_EXT_RSP:
          zclLight1_ProcessInDiscAttrsExtRspCmd( pInMsg );
          break;
    #endif
        default:
          break;
      }
    
      if ( pInMsg->attrCmd )
        osal_mem_free( pInMsg->attrCmd );
    }
    
    #ifdef ZCL_READ
    /***********************************************************
    
    
    
    
    *************************************************************/
    static uint8 zclLight1_ProcessInReadCmd( zclIncomingMsg_t *pInMsg )
    {
     
        HAL_TOGGLE_LED_Identify();
    
        return(TRUE);
    }
    
    
    
    
    /*********************************************************************
     * @fn      zclLight1_ProcessInReadRspCmd
     *
     * @brief   Process the "Profile" Read Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight1_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclReadRspCmd_t *readRspCmd;
      uint8 i;
    
      readRspCmd = (zclReadRspCmd_t *)pInMsg->attrCmd;
      for (i = 0; i < readRspCmd->numAttr; i++)
      {
        // Notify the originator of the results of the original read attributes
        // attempt and, for each successfull request, the value of the requested
        // attribute
      }
    
      return ( TRUE );
    }
    #endif // ZCL_READ
    
    #ifdef ZCL_WRITE
    /*********************************************************************
     * @fn      zclLight1_ProcessInWriteRspCmd
     *
     * @brief   Process the "Profile" Write Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight1_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclWriteRspCmd_t *writeRspCmd;
      uint8 i;
    
      writeRspCmd = (zclWriteRspCmd_t *)pInMsg->attrCmd;
      for ( i = 0; i < writeRspCmd->numAttr; i++ )
      {
        // Notify the device of the results of the its original write attributes
        // command.
      }
    
      return ( TRUE );
    }
    #endif // ZCL_WRITE
    
    /*********************************************************************
     * @fn      zclLight1_ProcessInDefaultRspCmd
     *
     * @brief   Process the "Profile" Default Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight1_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg )
    {
      // zclDefaultRspCmd_t *defaultRspCmd = (zclDefaultRspCmd_t *)pInMsg->attrCmd;
    
      // Device is notified of the Default Response command.
      (void)pInMsg;
    
      return ( TRUE );
    }
    
    #ifdef ZCL_DISCOVER
    /*********************************************************************
     * @fn      zclLight1_ProcessInDiscCmdsRspCmd
     *
     * @brief   Process the Discover Commands Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight1_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverCmdsCmdRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverCmdsCmdRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numCmd; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return ( TRUE );
    }
    
    /*********************************************************************
     * @fn      zclLight1_ProcessInDiscAttrsRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight1_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsRspCmd_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsRspCmd_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return ( TRUE );
    }
    
    /*********************************************************************
     * @fn      zclLight1_ProcessInDiscAttrsExtRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Extended Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight1_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsExtRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsExtRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return ( TRUE );
    }
    #endif // ZCL_DISCOVER
    
    #if ZCL_EZMODE
    /*********************************************************************
     * @fn      zclLight1_ProcessZDOMsgs
     *
     * @brief   Called when this node receives a ZDO/ZDP response.
     *
     * @param   none
     *
     * @return  status
     */
    static void zclLight1_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg )
    {
      zclEZMode_ActionData_t data;
      ZDO_MatchDescRsp_t *pMatchDescRsp;
    
      // Let EZ-Mode know of the Simple Descriptor Response
      if ( pMsg->clusterID == Match_Desc_rsp )
      {
        pMatchDescRsp = ZDO_ParseEPListRsp( pMsg );
        data.pMatchDescRsp = pMatchDescRsp;
        zcl_EZModeAction( EZMODE_ACTION_MATCH_DESC_RSP, &data );
        osal_mem_free( pMatchDescRsp );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight1_EZModeCB
     *
     * @brief   The Application is informed of events. This can be used to show on the UI what is
    *           going on during EZ-Mode steering/finding/binding.
     *
     * @param   state - an
     *
     * @return  none
     */
    static void zclLight1_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData )
    {
    #ifdef LCD_SUPPORTED
      char *pStr;
      uint8 err;
    #endif
    
      // time to go into identify mode
      if ( state == EZMODE_STATE_IDENTIFYING )
      {
    #ifdef LCD_SUPPORTED
        HalLcdWriteString( "EZMode", HAL_LCD_LINE_2 );
    #endif
    
        zclLight1_IdentifyTime = ( EZMODE_TIME / 1000 );  // convert to seconds
        zclLight1_ProcessIdentifyTimeChange();
      }
    
      // autoclosing, show what happened (success, cancelled, etc...)
      if( state == EZMODE_STATE_AUTOCLOSE )
      {
    #ifdef LCD_SUPPORTED
        pStr = NULL;
        err = pData->sAutoClose.err;
        if ( err == EZMODE_ERR_SUCCESS )
        {
          pStr = "EZMode: Success";
        }
        else if ( err == EZMODE_ERR_NOMATCH )
        {
          pStr = "EZMode: NoMatch"; // not a match made in heaven
        }
        if ( pStr )
        {
          if ( giLightScreenMode == LIGHT_MAINMODE )
          {
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
          }
        }
    #endif
      }
    
      // finished, either show DstAddr/EP, or nothing (depending on success or not)
      if( state == EZMODE_STATE_FINISH )
      {
        // turn off identify mode
        zclLight1_IdentifyTime = 0;
        zclLight1_ProcessIdentifyTimeChange();
    
    #ifdef LCD_SUPPORTED
        // if successful, inform user which nwkaddr/ep we bound to
        pStr = NULL;
        err = pData->sFinish.err;
        if( err == EZMODE_ERR_SUCCESS )
        {
          // already stated on autoclose
        }
        else if ( err == EZMODE_ERR_CANCELLED )
        {
          pStr = "EZMode: Cancel";
        }
        else if ( err == EZMODE_ERR_BAD_PARAMETER )
        {
          pStr = "EZMode: BadParm";
        }
        else if ( err == EZMODE_ERR_TIMEDOUT )
        {
          pStr = "EZMode: TimeOut";
        }
        if ( pStr )
        {
          if ( giLightScreenMode == LIGHT_MAINMODE )
          {
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
          }
        }
    #endif
        // show main UI screen 3 seconds after binding
        osal_start_timerEx( zclMultiSensor_TaskID, LIGHT_MAIN_SCREEN_EVT, 3000 );
      }
    }
    #endif // ZCL_EZMODE
    
    static void zclMultiSensor_ReadSensors(void)
    {
        //*****Read LightSensor Value*****
        HalAdcSetReference(HAL_ADC_REF_AVDD);
        adc_value = HalAdcRead (HAL_ADC_CHN_AIN7, HAL_ADC_RESOLUTION_14);//read LDR 
        zclLightSensor_MeasuredValue=adc_value;
        if(zclLightSensor_MeasuredValue < MIN_ILLUMINANCE)
        {
          zclLightSensor_SendIlluminance();   
          
        }
        
        //*****Read Battery Voltage*****
        
        HalAdcSetReference(HAL_ADC_REF_125V);
        adc_value = HalAdcRead (HAL_ADC_CHN_VDD3, HAL_ADC_RESOLUTION_8);
        adc_value = adc_value *(3.57/128)*100;
        zclNode_BatteryVoltage = adc_value;   
        //check if battery is low   
        if (zclNode_BatteryVoltage < MIN_BAT_VOLTAGE)
        {
          zclNode_AlarmMask = BAT_ALARM_MASK_VOLT_2_LOW;
          zclGeneral_SendAlarm( OCCUPANCYSENSOR_ENDPOINT, &zclOccupancySensor_DstAddr,
                                   ALARM_CODE_BAT_VOLT_MIN_THRES_BAT_SRC_1, ZCL_CLUSTER_ID_GEN_POWER_CFG,
                                    TRUE, zclMultiSensorSeqNum); 
          //HAL_TOGGLE_LED_Identify();
        }
        else
        {
          zclNode_AlarmMask = 0x00;
          
        }
    }
    
    
    static void zclLightSensor_SendIlluminance( void )
    {
    #ifdef ZCL_REPORT
      zclReportCmd_t *pReportCmd;
    
      pReportCmd = osal_mem_alloc( sizeof(zclReportCmd_t) + sizeof(zclReport_t) );
      if ( pReportCmd != NULL )
      {
        pReportCmd->numAttr = 1;
        pReportCmd->attrList[0].attrID = ATTRID_MS_ILLUMINANCE_MEASURED_VALUE;
        pReportCmd->attrList[0].dataType = ZCL_DATATYPE_INT16;
        pReportCmd->attrList[0].attrData =(void *)&zclLightSensor_MeasuredValue;
    
        zcl_SendReportCmd( LIGHTSENSOR_ENDPOINT, &zclLightSensor_DstAddr,
                           ZCL_CLUSTER_ID_MS_ILLUMINANCE_MEASUREMENT,
                           pReportCmd, ZCL_FRAME_SERVER_CLIENT_DIR, TRUE, zclMultiSensorSeqNum++ );
      }
    
      osal_mem_free( pReportCmd );
    #endif  // ZCL_REPORT
    }
    
    /************************************************/
    
    
    
    /*************************************************/
    static void zclMultiSensor_PIR_SenseMv(void)
    {
      Mv_Cnt++;
      if( PIR_flag )
      {
        osal_start_timerEx( zclMultiSensor_TaskID, zclOccupancySensor_UtoO_TIMER_EVT,(zclOccupancySensor_UtoODelay*1000) );
        PIR_flag = FALSE;
      }
    }
    
    /****************************************************/
    
    
    
    /****************************************************/
    static void zclMultiSensor_CheckPIR(void)
    {
      
      //must disable interrupts here
      if(Mv_Cnt >= zclOccupancySensor_UtoOThresh)
      {
          Mv_Cnt = 0 ;
          PIR_flag = TRUE;
          zclOccupancySensor_Occupancy = 0x01;
          osal_stop_timerEx( zclMultiSensor_TaskID, zclOccupancySensor_OtoU_TIMER_EVT );
          osal_start_timerEx( zclMultiSensor_TaskID, zclOccupancySensor_OtoU_TIMER_EVT,(zclOccupancySensor_OtoUDelay*1000) );
      }
      else
      {
          Mv_Cnt = 0 ;
          PIR_flag = TRUE ;
          zclOccupancySensor_Occupancy = 0x00;
      }
      
      if ( zclOccupancySensor_Occupancy != zclOccupancySensor_LastOccupancy)
      {
        zclOccupancySensor_LastOccupancy = zclOccupancySensor_Occupancy;
        zclOccupancySensor_SendOccupancy();
      }
     
    }
    
    /*********************************************************/
    
    
    /***********************************************************/
    static void zclOccupancySensor_SendOccupancy(void)
    {
    #ifdef ZCL_REPORT
      zclReportCmd_t *pReportCmd;
    
      pReportCmd = osal_mem_alloc( sizeof(zclReportCmd_t) + sizeof(zclReport_t) );
      if ( pReportCmd != NULL )
      {
        pReportCmd->numAttr = 1;
        pReportCmd->attrList[0].attrID = ATTRID_MS_OCCUPANCY_SENSING_CONFIG_OCCUPANCY;
        pReportCmd->attrList[0].dataType = ZCL_DATATYPE_BITMAP8;
        pReportCmd->attrList[0].attrData =(void *)&zclOccupancySensor_Occupancy;
    
        zcl_SendReportCmd( OCCUPANCYSENSOR_ENDPOINT, &zclOccupancySensor_DstAddr,
                           ZCL_CLUSTER_ID_MS_OCCUPANCY_SENSING,
                           pReportCmd, ZCL_FRAME_SERVER_CLIENT_DIR, TRUE, zclMultiSensorSeqNum++ );
      }
    
      osal_mem_free( pReportCmd );
    #endif  // ZCL_REPORT  
      
    }  
    
    /****************************************************************************
    ****************************************************************************/
    
    
    
    /**************************************************************************************************
      Filename:       zcl_samplesw.c
      Revised:        $Date: 2014-10-24 16:04:46 -0700 (Fri, 24 Oct 2014) $
      Revision:       $Revision: 40796 $
    
      Description:    Zigbee Cluster Library - sample device application.
    
    
      Copyright 2006-2013 Texas Instruments Incorporated. All rights reserved.
    
      IMPORTANT: Your use of this Software is limited to those specific rights
      granted under the terms of a software license agreement between the user
      who downloaded the software, his/her employer (which must be your employer)
      and Texas Instruments Incorporated (the "License").  You may not use this
      Software unless you agree to abide by the terms of the License. The License
      limits your use, and you acknowledge, that the Software may not be modified,
      copied or distributed unless embedded on a Texas Instruments microcontroller
      or used solely and exclusively in conjunction with a Texas Instruments radio
      frequency transceiver, which is integrated into your product.  Other than for
      the foregoing purpose, you may not use, reproduce, copy, prepare derivative
      works of, modify, distribute, perform, display or sell this Software and/or
      its documentation for any purpose.
    
      YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
      PROVIDED �AS IS� WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
      INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
      NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
      TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
      NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
      LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
      INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
      OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
      OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
      (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
    
      Should you have any questions regarding your right to use this Software,
      contact Texas Instruments Incorporated at www.TI.com.
    **************************************************************************************************/
    
    /*********************************************************************
      This device will be like an On/Off Switch device. This application
      is not intended to be a On/Off Switch device, but will use the device
      description to implement this sample code.
    
      ----------------------------------------
      Main:
        - SW1: Toggle remote light
        - SW2: Invoke EZMode
        - SW4: Enable/Disable Permit Join
        - SW5: Go to Help screen
      ----------------------------------------
    *********************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    #include "ZComDef.h"
    #include "OSAL.h"
    #include "AF.h"
    #include "ZDApp.h"
    #include "ZDObject.h"
    #include "ZDProfile.h"
    #include "MT_SYS.h"
    
    #include "zcl.h"
    #include "zcl_general.h"
    #include "zcl_ha.h"
    #include "zcl_sw.h"
    #include "zcl_ezmode.h"
    
    #include "onboard.h"
    
    /* HAL */
    #include "hal_lcd.h"
    #include "hal_led.h"
    #include "hal_key.h"
    
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    #include "zcl_ota.h"
    #include "hal_ota.h"
    #endif
    
    /****mine***/
    #include "zcl_ms.h"
    #include "hal_uart.h"
    #include <stdio.h>
    /*********************************************************************
     * MACROS
     */
    
    /*********************************************************************
     * CONSTANTS
     */
    /*********************************************************************
     * TYPEDEFS
     */
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    byte zclSw_TaskID;
    
    uint8 zclSwSeqNum;
    
    uint8 zclSw_OnOffSwitchType = ON_OFF_SWITCH_TYPE_TOGGLE;
    
    uint8 zclSw_OnOffSwitchActions = ON_OFF_SWITCH_ACTIONS_2;   // Toggle -> Toggle
    
    /*********************************************************************
     * GLOBAL FUNCTIONS
     */
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    
    uint16 zclSw_LocalIlluminance;//mine
    
    #ifdef ZCL_ON_OFF
    afAddrType_t zclSw_DstAddr;
    afAddrType_t zclSw_DstAddr_2;
    #endif
    
    #ifdef ZCL_EZMODE
    static void zclSw_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg );
    static void zclSw_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData );
    
    static const zclEZMode_RegisterData_t zclSw_RegisterEZModeData =
    {
      &zclSw_TaskID,
      SW_EZMODE_NEXTSTATE_EVT,
      SW_EZMODE_TIMEOUT_EVT,
      &zclSwSeqNum,
      zclSw_EZModeCB
    };
    
    // NOT ZLC_EZMODE, Use EndDeviceBind
    #else
    
    static cId_t bindingOutClusters[] =
    {
      ZCL_CLUSTER_ID_GEN_ON_OFF
    };
    #define ZCLSW_BINDINGLIST   (sizeof(bindingOutClusters)/sizeof(bindingOutClusters[0]))
    #endif  // ZLC_EZMODE
    
    // Endpoint to allow SYS_APP_MSGs
    static endPointDesc_t sampleSw_TestEp =
    {
      SW_ENDPOINT,                  // endpoint
      &zclSw_TaskID,
      (SimpleDescriptionFormat_t *)NULL,  // No Simple description for this test endpoint
      (afNetworkLatencyReq_t)0            // No Network Latency req
    };
    
    uint8 giSwScreenMode = SW_MAINMODE;   // display the main screen mode first
    
    static uint8 aProcessCmd[] = { 1, 0, 0, 0 }; // used for reset command, { length + cmd0 + cmd1 + data }
    
    uint8 gPermitDuration = 0;    // permit joining default to disabled
    
    devStates_t zclSw_NwkState = DEV_INIT;
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    #define DEVICE_POLL_RATE                 8000   // Poll rate for end device
    #endif
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    static void zclSw_HandleKeys( byte shift, byte keys );
    static void zclSw_BasicResetCB( void );
    static void zclSw_IdentifyCB( zclIdentify_t *pCmd );
    static void zclSw_IdentifyQueryRspCB(  zclIdentifyQueryRsp_t *pRsp );
    static void zclSw_ProcessIdentifyTimeChange( void );
    
    static void zclSw_AlarmsCB( uint8 direction, zclAlarm_t *pAlarm );
    
    // app display functions
    void zclSw_LcdDisplayUpdate(void);
    void zclSw_LcdDisplayMainMode(void);
    void zclSw_LcdDisplayHelpMode(void);
    
    // Functions to process ZCL Foundation incoming Command/Response messages
    static void zclSw_ProcessIncomingMsg( zclIncomingMsg_t *msg );
    #ifdef ZCL_READ
    static uint8 zclSw_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    #ifdef ZCL_WRITE
    static uint8 zclSw_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    static uint8 zclSw_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg );
    #ifdef ZCL_DISCOVER
    static uint8 zclSw_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclSw_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclSw_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    static void zclSw_ProcessOTAMsgs( zclOTA_CallbackMsg_t* pMsg );
    #endif
    
    #ifdef ZCL_REPORT
    static void zclSw_ProcessInReportCmd (zclIncomingMsg_t *pInMsg);
    #endif
    
    /*********************************************************************
     * ZCL General Profile Callback table
     */
    static zclGeneral_AppCallbacks_t zclSw_CmdCallbacks =
    {
      zclSw_BasicResetCB,               // Basic Cluster Reset command
      zclSw_IdentifyCB,                 // Identify command
    #ifdef ZCL_EZMODE
      NULL,                                   // Identify EZ-Mode Invoke command
      NULL,                                   // Identify Update Commission State command
    #endif
      NULL,                                   // Identify Trigger Effect command
      zclSw_IdentifyQueryRspCB,         // Identify Query Response command
      NULL,                                   // On/Off cluster commands
      NULL,                                   // On/Off cluster enhanced command Off with Effect
      NULL,                                   // On/Off cluster enhanced command On with Recall Global Scene
      NULL,                                   // On/Off cluster enhanced command On with Timed Off
    #ifdef ZCL_LEVEL_CTRL
      NULL,                                   // Level Control Move to Level command
      NULL,                                   // Level Control Move command
      NULL,                                   // Level Control Step command
      NULL,                                   // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPS
      NULL,                                   // Group Response commands
    #endif
    #ifdef ZCL_SCENES
      NULL,                                   // Scene Store Request command
      NULL,                                   // Scene Recall Request command
      NULL,                                   // Scene Response command
    #endif
    #ifdef ZCL_ALARMS
      zclSw_AlarmsCB,                                   // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXT
      NULL,                                   // Get Event Log command
      NULL,                                   // Publish Event Log command
    #endif
      NULL,                                   // RSSI Location command
      NULL                                    // RSSI Location Response command
    };
    
    
    /*********************************************************************
     * STATUS STRINGS
     */
    #ifdef LCD_SUPPORTED
    const char sDeviceName[]   = "  Sample Switch";
    const char sClearLine[]    = " ";
    const char sSwLight[]      = "SW1: ToggleLight";
    const char sSwEZMode[]     = "SW2: EZ-Mode";
    const char sSwHelp[]       = "SW5: Help";
    const char sCmdSent[]      = "  COMMAND SENT";
    #endif
    
    /*********************************************************************
     * @fn          zclSw_Init
     *
     * @brief       Initialization function for the zclGeneral layer.
     *
     * @param       none
     *
     * @return      none
     */
    void zclSw_Init( byte task_id )
    {
      zclSw_TaskID = task_id;
    
    #ifdef ZCL_ON_OFF
      // Set destination address to indirect
      zclSw_DstAddr.addrMode = (afAddrMode_t)AddrGroup;
      zclSw_DstAddr.endPoint = 0;
      zclSw_DstAddr.addr.shortAddr = 0;
      
      /************mine**************/
      zclSw_DstAddr_2.addrMode = (afAddrMode_t)AddrGroup;
      zclSw_DstAddr_2.endPoint = 0;
      zclSw_DstAddr_2.addr.shortAddr = 1;
      /****************************/
      
    #endif
    
      // This app is part of the Home Automation Profile
      zclHA_Init( &zclSw_SimpleDesc );
    
      // Register the ZCL General Cluster Library callback functions
      zclGeneral_RegisterCmdCallbacks( SW_ENDPOINT, &zclSw_CmdCallbacks );
    
      // Register the application's attribute list
      zcl_registerAttrList( SW_ENDPOINT, SW_MAX_ATTRIBUTES, zclSw_Attrs );
    
      // Register the Application to receive the unprocessed Foundation command/response messages
      zcl_registerForMsg( zclSw_TaskID );
    
    #ifdef ZCL_EZMODE
      // Register EZ-Mode
      zcl_RegisterEZMode( &zclSw_RegisterEZModeData );
    
      // Register with the ZDO to receive Match Descriptor Responses
      ZDO_RegisterForZDOMsg(task_id, Match_Desc_rsp);
    #endif
    
      // Register for all key events - This app will handle all key events
      RegisterForKeys( zclSw_TaskID );
    
      // Register for a test endpoint
      afRegister( &sampleSw_TestEp );
    
      ZDO_RegisterForZDOMsg( zclSw_TaskID, End_Device_Bind_rsp );
      ZDO_RegisterForZDOMsg( zclSw_TaskID, Match_Desc_rsp );
    
    #ifdef LCD_SUPPORTED
      HalLcdWriteString ( (char *)sDeviceName, HAL_LCD_LINE_3 );
    #endif
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
      // Register for callback events from the ZCL OTA
      zclOTA_Register(zclSw_TaskID);
    #endif
      
    
    }
    
    /*********************************************************************
     * @fn          zclSample_event_loop
     *
     * @brief       Event Loop Processor for zclGeneral.
     *
     * @param       none
     *
     * @return      none
     */
    uint16 zclSw_event_loop( uint8 task_id, uint16 events )
    {
      afIncomingMSGPacket_t *MSGpkt;
      (void)task_id;  // Intentionally unreferenced parameter
    
      if ( events & SYS_EVENT_MSG )
      {
        while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( zclSw_TaskID )) )
        {
          switch ( MSGpkt->hdr.event )
          {
    #ifdef ZCL_EZMODE
            case ZDO_CB_MSG:
              zclSw_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
              break;
    #endif
            case ZCL_INCOMING_MSG:
              // Incoming ZCL Foundation command/response messages
              zclSw_ProcessIncomingMsg( (zclIncomingMsg_t *)MSGpkt );
              break;
    
            case KEY_CHANGE:
              zclSw_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
              break;
    
            case ZDO_STATE_CHANGE:
              zclSw_NwkState = (devStates_t)(MSGpkt->hdr.status);
    
              // now on the network
              if ( (zclSw_NwkState == DEV_ZB_COORD) ||
                   (zclSw_NwkState == DEV_ROUTER)   ||
                   (zclSw_NwkState == DEV_END_DEVICE) )
              {
    #ifndef HOLD_AUTO_START
                giSwScreenMode = SW_MAINMODE;
                zclSw_LcdDisplayUpdate();
    #endif
    #ifdef ZCL_EZMODE
                zcl_EZModeAction( EZMODE_ACTION_NETWORK_STARTED, NULL );
    #endif
              }
              break;
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
            case ZCL_OTA_CALLBACK_IND:
              zclSw_ProcessOTAMsgs( (zclOTA_CallbackMsg_t*)MSGpkt  );
              break;
    #endif
    
            default:
              break;
          }
    
          // Release the memory
          osal_msg_deallocate( (uint8 *)MSGpkt );
        }
    
        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
      }
    
      if ( events & SW_IDENTIFY_TIMEOUT_EVT )
      {
        zclSw_IdentifyTime = 10;
        zclSw_ProcessIdentifyTimeChange();
    
        return ( events ^ SW_IDENTIFY_TIMEOUT_EVT );
      }
    
      if ( events & SW_MAIN_SCREEN_EVT )
      {
        giSwScreenMode = SW_MAINMODE;
    
        zclSw_LcdDisplayUpdate();
    
    #ifdef LCD_SUPPORTED
        HalLcdWriteString( (char *)sClearLine, HAL_LCD_LINE_2 );
    #endif
        return ( events ^ SW_MAIN_SCREEN_EVT );
      }
    
    #ifdef ZCL_EZMODE
      if ( events & SW_EZMODE_NEXTSTATE_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_PROCESS, NULL );   // going on to next state
        return ( events ^ SW_EZMODE_NEXTSTATE_EVT );
      }
    
      if ( events & SW_EZMODE_TIMEOUT_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_TIMED_OUT, NULL ); // EZ-Mode timed out
        return ( events ^ SW_EZMODE_TIMEOUT_EVT );
      }
    #endif // ZLC_EZMODE
    
      // Discard unknown events
      return 0;
    }
    
    /*********************************************************************
     * @fn      zclSw_HandleKeys
     *
     * @brief   Handles all key events for this device.
     *
     * @param   shift - true if in shift/alt.
     * @param   keys - bit field for key events. Valid entries:
     *                 HAL_KEY_SW_5
     *                 HAL_KEY_SW_4
     *                 HAL_KEY_SW_2
     *                 HAL_KEY_SW_1
     *
     * @return  none
     */
    static void zclSw_HandleKeys( byte shift, byte keys )
    {
      // toggle remote light
      if ( keys & HAL_KEY_SW_1 )
      {
        giSwScreenMode = SW_MAINMODE;   // remove help screen if there
    
        // Using this as the "Light Switch"
    #ifdef ZCL_ON_OFF
       // zclGeneral_SendOnOff_CmdToggle( SW_ENDPOINT, &zclSw_DstAddr, FALSE, 0 );
    #endif
    /***********************Send Read Cmd******************/
    /**************************mine************************/    
        
      zclReadCmd_t *pReadCmd;
      ZStatus_t status;
      pReadCmd = osal_mem_alloc( sizeof(zclReadCmd_t)+sizeof(uint16));
      if ( pReadCmd != NULL )
      {
        pReadCmd->numAttr = 1;
        pReadCmd->attrID[0] = ATTRID_ON_OFF;
        status = zcl_SendRead( SW_ENDPOINT, &zclSw_DstAddr,ZCL_CLUSTER_ID_GEN_ON_OFF,pReadCmd,ZCL_FRAME_CLIENT_SERVER_DIR, 0, zclSwSeqNum);
        if(status == SUCCESS)
        {
          HAL_TOGGLE_LED1() ;
        }
      }
      
    
      osal_mem_free( pReadCmd ); 
      
    
    /***********************************************************/    
    
    #ifdef LCD_SUPPORTED
        HalLcdWriteString( (char *)sCmdSent, HAL_LCD_LINE_2 );
    
        // clear message on screen after 3 seconds
        osal_start_timerEx( zclSw_TaskID, SW_MAIN_SCREEN_EVT, 3000 );
    #endif
      }
    
      // invoke EZ-Mode
      if ( keys & HAL_KEY_SW_2 )
      {
     
      }
    
      // toggle permit join
      if ( keys & HAL_KEY_SW_4 )
      {
    
      }
    
      if ( keys & HAL_KEY_SW_5 )
      {
        giSwScreenMode = giSwScreenMode ? SW_MAINMODE : SW_HELPMODE;
        //zclGeneral_SendOnOff_CmdToggle( SW_ENDPOINT, &zclSw_DstAddr_2, FALSE, 0 );//mine
        
        #ifdef LCD_SUPPORTED
        HalLcdWriteString( (char *)sCmdSent, HAL_LCD_LINE_2 );
    
        // clear message on screen after 3 seconds
        osal_start_timerEx( zclSw_TaskID, SW_MAIN_SCREEN_EVT, 3000 );
        #endif
      }
    
      // update the display
      zclSw_LcdDisplayUpdate();
    }
    
    /*********************************************************************
     * @fn      zclSw_LcdDisplayUpdate
     *
     * @brief   Called to update the LCD display.
     *
     * @param   none
     *
     * @return  none
     */
    void zclSw_LcdDisplayUpdate(void)
    {
      if ( giSwScreenMode == SW_HELPMODE )
      {
        zclSw_LcdDisplayHelpMode();
      }
      else
      {
        zclSw_LcdDisplayMainMode();
      }
    }
    
    /*********************************************************************
     * @fn      zclSw_LcdDisplayMainMode
     *
     * @brief   Called to display the main screen on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    void zclSw_LcdDisplayMainMode(void)
    {
      if ( zclSw_NwkState == DEV_ZB_COORD )
      {
        zclHA_LcdStatusLine1(0);
      }
      else if ( zclSw_NwkState == DEV_ROUTER )
      {
        zclHA_LcdStatusLine1(1);
      }
      else if ( zclSw_NwkState == DEV_END_DEVICE )
      {
        zclHA_LcdStatusLine1(2);
      }
    
    #ifdef LCD_SUPPORTED
      if ( ( zclSw_NwkState == DEV_ZB_COORD ) ||
           ( zclSw_NwkState == DEV_ROUTER ) )
      {
        // display help key with permit join status
        if ( gPermitDuration )
        {
          HalLcdWriteString("SW5: Help      *", HAL_LCD_LINE_3);
        }
        else
        {
          HalLcdWriteString("SW5: Help       ", HAL_LCD_LINE_3);
        }
      }
      else
      {
        // display help key
        HalLcdWriteString((char *)sSwHelp, HAL_LCD_LINE_3);
      }
    #endif
    }
    
    /*********************************************************************
     * @fn      zclSw_LcdDisplayHelpMode
     *
     * @brief   Called to display the SW options on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    void zclSw_LcdDisplayHelpMode(void)
    {
    #ifdef LCD_SUPPORTED
      HalLcdWriteString( (char *)sSwLight, HAL_LCD_LINE_1 );
      HalLcdWriteString( (char *)sSwEZMode, HAL_LCD_LINE_2 );
      HalLcdWriteString( (char *)sSwHelp, HAL_LCD_LINE_3 );
    #endif
    }
    
    /*********************************************************************
     * @fn      zclSw_ProcessIdentifyTimeChange
     *
     * @brief   Called to process any change to the IdentifyTime attribute.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclSw_ProcessIdentifyTimeChange( void )
    {
      if ( zclSw_IdentifyTime > 0 )
      {
        osal_start_timerEx( zclSw_TaskID, SW_IDENTIFY_TIMEOUT_EVT, 1000 );
        HalLedBlink ( HAL_LED_4, 0xFF, HAL_LED_DEFAULT_DUTY_CYCLE, HAL_LED_DEFAULT_FLASH_TIME );
      }
      else
      {
        if ( zclSw_OnOff )
          HalLedSet ( HAL_LED_4, HAL_LED_MODE_ON );
        else
          HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
        osal_stop_timerEx( zclSw_TaskID, SW_IDENTIFY_TIMEOUT_EVT );
      }
    }
    
    /*********************************************************************
     * @fn      zclSw_BasicResetCB
     *
     * @brief   Callback from the ZCL General Cluster Library
     *          to set all the Basic Cluster attributes to  default values.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclSw_BasicResetCB( void )
    {
      // Put device back to factory default settings
      zgWriteStartupOptions( ZG_STARTUP_SET, 3 );   // bit set both default configuration and default network
    
      // restart device
      MT_SysCommandProcessing( aProcessCmd );
    }
    
    
    /************************************************/
    
    static void zclSw_AlarmsCB( uint8 direction, zclAlarm_t *pAlarm )
    {
      if(pAlarm -> alarmCode == ALARM_CODE_BAT_VOLT_MIN_THRES_BAT_SRC_1)
      {
        HAL_TOGGLE_LED2();
      }
      else
      {
         // HAL_TOGGLE_LED1();
      }
        
      
    }
    
    
    
    /******************************************************/
    
    /*********************************************************************
     * @fn      zclSw_IdentifyCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Command for this application.
     *
     * @param   srcAddr - source address and endpoint of the response message
     * @param   identifyTime - the number of seconds to identify yourself
     *
     * @return  none
     */
    static void zclSw_IdentifyCB( zclIdentify_t *pCmd )
    {
      zclSw_IdentifyTime = pCmd->identifyTime;
      zclSw_ProcessIdentifyTimeChange();
    }
    
    /*********************************************************************
     * @fn      zclSw_IdentifyQueryRspCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Query Response Command for this application.
     *
     * @param   srcAddr - source address
     * @param   timeout - number of seconds to identify yourself (valid for query response)
     *
     * @return  none
     */
    static void zclSw_IdentifyQueryRspCB(  zclIdentifyQueryRsp_t *pRsp )
    {
      (void)pRsp;
    #ifdef ZCL_EZMODE
      {
        zclEZMode_ActionData_t data;
        data.pIdentifyQueryRsp = pRsp;
        zcl_EZModeAction ( EZMODE_ACTION_IDENTIFY_QUERY_RSP, &data );
      }
    #endif
    }
    
    /******************************************************************************
     *
     *  Functions for processing ZCL Foundation incoming Command/Response messages
     *
     *****************************************************************************/
    
    /*********************************************************************
     * @fn      zclSw_ProcessIncomingMsg
     *
     * @brief   Process ZCL Foundation incoming message
     *
     * @param   pInMsg - pointer to the received message
     *
     * @return  none
     */
    static void zclSw_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg )
    {
      switch ( pInMsg->zclHdr.commandID )
      {
    #ifdef ZCL_READ
        case ZCL_CMD_READ_RSP:
          zclSw_ProcessInReadRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_WRITE
        case ZCL_CMD_WRITE_RSP:
          zclSw_ProcessInWriteRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_REPORT
        // See ZCL Test Applicaiton (zcl_testapp.c) for sample code on Attribute Reporting
        case ZCL_CMD_CONFIG_REPORT:
          //zclSw_ProcessInConfigReportCmd( pInMsg );
          break;
    
        case ZCL_CMD_CONFIG_REPORT_RSP:
          //zclSw_ProcessInConfigReportRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG:
          //zclSw_ProcessInReadReportCfgCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG_RSP:
          //zclSw_ProcessInReadReportCfgRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_REPORT:
          zclSw_ProcessInReportCmd( pInMsg );
          break;
    #endif
        case ZCL_CMD_DEFAULT_RSP:
          zclSw_ProcessInDefaultRspCmd( pInMsg );
          break;
    #ifdef ZCL_DISCOVER
        case ZCL_CMD_DISCOVER_CMDS_RECEIVED_RSP:
          zclSw_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_CMDS_GEN_RSP:
          zclSw_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_RSP:
          zclSw_ProcessInDiscAttrsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_EXT_RSP:
          zclSw_ProcessInDiscAttrsExtRspCmd( pInMsg );
          break;
    #endif
        default:
          break;
      }
    
      if ( pInMsg->attrCmd )
        osal_mem_free( pInMsg->attrCmd );
    }
    
    #ifdef ZCL_READ
    /*********************************************************************
     * @fn      zclSw_ProcessInReadRspCmd
     *
     * @brief   Process the "Profile" Read Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclReadRspCmd_t *readRspCmd;
      uint8 i;
    
      readRspCmd = (zclReadRspCmd_t *)pInMsg->attrCmd;
      for (i = 0; i < readRspCmd->numAttr; i++)
      {
        // Notify the originator of the results of the original read attributes
        // attempt and, for each successfull request, the value of the requested
        // attribute
      }
    
      return TRUE;
    }
    #endif // ZCL_READ
    
    #ifdef ZCL_WRITE
    /*********************************************************************
     * @fn      zclSw_ProcessInWriteRspCmd
     *
     * @brief   Process the "Profile" Write Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclWriteRspCmd_t *writeRspCmd;
      uint8 i;
    
      writeRspCmd = (zclWriteRspCmd_t *)pInMsg->attrCmd;
      for (i = 0; i < writeRspCmd->numAttr; i++)
      {
        // Notify the device of the results of the its original write attributes
        // command.
      }
    
      return TRUE;
    }
    #endif // ZCL_WRITE
    
    /*********************************************************************
     * @fn      zclSw_ProcessInDefaultRspCmd
     *
     * @brief   Process the "Profile" Default Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg )
    {
      // zclDefaultRspCmd_t *defaultRspCmd = (zclDefaultRspCmd_t *)pInMsg->attrCmd;
      // Device is notified of the Default Response command.
      (void)pInMsg;
      return TRUE;
    }
    
    #ifdef ZCL_DISCOVER
    /*********************************************************************
     * @fn      zclSw_ProcessInDiscCmdsRspCmd
     *
     * @brief   Process the Discover Commands Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverCmdsCmdRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverCmdsCmdRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numCmd; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return TRUE;
    }
    
    /*********************************************************************
     * @fn      zclSw_ProcessInDiscAttrsRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsRspCmd_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsRspCmd_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return TRUE;
    }
    
    /*********************************************************************
     * @fn      zclSw_ProcessInDiscAttrsExtRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Extended Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsExtRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsExtRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return TRUE;
    }
    #endif // ZCL_DISCOVER
    
    
    
    /*********************************************************************
     * @fn      zclSampleSw_ProcessInReportCmd
     *
     * @brief   Process the "Profile" Report Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    
    static void zclSw_ProcessInReportCmd( zclIncomingMsg_t *pInMsg )
    {
      zclReportCmd_t *pInLightSensorReport;
      uint16 cli = pInMsg -> clusterId; // cluster Id
    
      pInLightSensorReport = (zclReportCmd_t *)pInMsg->attrCmd;
    
      if ( cli == ZCL_CLUSTER_ID_MS_ILLUMINANCE_MEASUREMENT && pInLightSensorReport->attrList[0].attrID == ATTRID_MS_ILLUMINANCE_MEASURED_VALUE )
      {
      zclSw_LocalIlluminance = BUILD_UINT16(pInLightSensorReport->attrList[0].attrData[0], pInLightSensorReport->attrList[0].attrData[1]);
      uint8 buf[30]="";
      sprintf(buf,"LDR Voltage is = %u\n\r\0",zclSw_LocalIlluminance);
      HalUARTWrite(UART1_BASE,buf, sizeof(buf));  
      HAL_TOGGLE_LED4();
      }
      if (cli == ZCL_CLUSTER_ID_MS_OCCUPANCY_SENSING && pInLightSensorReport->attrList[0].attrID == ATTRID_MS_OCCUPANCY_SENSING_CONFIG_OCCUPANCY)
      {
        HAL_TOGGLE_LED1();
        
      }
    
    
      }
    
    
    #if ZCL_EZMODE
    /*********************************************************************
     * @fn      zclSw_ProcessZDOMsgs
     *
     * @brief   Called when this node receives a ZDO/ZDP response.
     *
     * @param   none
     *
     * @return  status
     */
    static void zclSw_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg )
    {
    
      // Let EZ-Mode know of the Match Descriptor Reponse (same as ActiveEP Response)
      if ( pMsg->clusterID == Match_Desc_rsp )
      {
        zclEZMode_ActionData_t data;
        ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( pMsg );
        data.pMatchDescRsp = pRsp;
        zcl_EZModeAction( EZMODE_ACTION_MATCH_DESC_RSP, &data );
        osal_mem_free(pRsp);
      }
    }
    
    /*********************************************************************
     * @fn      zclSw_EZModeCB
     *
     * @brief   The Application is informed of events. This can be used to show on the UI what is
    *           going on during EZ-Mode steering/finding/binding.
     *
     * @param   state - an
     *
     * @return  none
     */
    static void zclSw_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData )
    {
    #ifdef LCD_SUPPORTED
      char szLine[20];
      char *pStr;
      uint8 err;
    #endif
    
      // time to go into identify mode
      if ( state == EZMODE_STATE_IDENTIFYING )
      {
        zclSw_IdentifyTime = (EZMODE_TIME / 1000);  // convert to seconds
        zclSw_ProcessIdentifyTimeChange();
      }
    
      // autoclosing, show what happened (success, cancelled, etc...)
      if( state == EZMODE_STATE_AUTOCLOSE )
      {
    #ifdef LCD_SUPPORTED
        pStr = NULL;
        err = pData->sAutoClose.err;
        if ( err == EZMODE_ERR_SUCCESS )
        {
          pStr = "EZMode: Success";
        }
        else if ( err == EZMODE_ERR_NOMATCH )
        {
          pStr = "EZMode: NoMatch"; // not a match made in heaven
        }
        if ( pStr )
        {
          if ( giSwScreenMode == SW_MAINMODE )
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
        }
    #endif
      }
    
      // finished, either show DstAddr/EP, or nothing (depending on success or not)
      if( state == EZMODE_STATE_FINISH )
      {
        // turn off identify mode
        zclSw_IdentifyTime = 0;
        zclSw_ProcessIdentifyTimeChange();
    
    #ifdef LCD_SUPPORTED
        // if successful, inform user which nwkaddr/ep we bound to
        pStr = NULL;
        err = pData->sFinish.err;
        if( err == EZMODE_ERR_SUCCESS )
        {
          // "EZDst:1234 EP:34"
          osal_memcpy(szLine, "EZDst:", 6);
          zclHA_uint16toa( pData->sFinish.nwkaddr, &szLine[6]);
          osal_memcpy(&szLine[10], " EP:", 4);
          _ltoa( pData->sFinish.ep, (void *)(&szLine[14]), 16 );  // _ltoa NULL terminates
          pStr = szLine;
        }
        else if ( err == EZMODE_ERR_BAD_PARAMETER )
        {
          pStr = "EZMode: BadParm";
        }
        else if ( err == EZMODE_ERR_CANCELLED )
        {
          pStr = "EZMode: Cancel";
        }
        else
        {
          pStr = "EZMode: TimeOut";
        }
        if ( pStr )
        {
          if ( giSwScreenMode == SW_MAINMODE )
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
        }
    #endif  // LCD_SUPPORTED
        // show main UI screen 3 seconds after binding
        osal_start_timerEx( zclSw_TaskID, SW_MAIN_SCREEN_EVT, 3000 );
      }
    
    }
    
    #endif // ZCL_EZMODE
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    /*********************************************************************
     * @fn      zclSw_ProcessOTAMsgs
     *
     * @brief   Called to process callbacks from the ZCL OTA.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclSw_ProcessOTAMsgs( zclOTA_CallbackMsg_t* pMsg )
    {
      uint8 RxOnIdle;
    
      switch(pMsg->ota_event)
      {
      case ZCL_OTA_START_CALLBACK:
        if (pMsg->hdr.status == ZSuccess)
        {
          // Speed up the poll rate
          RxOnIdle = TRUE;
          ZMacSetReq( ZMacRxOnIdle, &RxOnIdle );
          NLME_SetPollRate( 2000 );
        }
        break;
    
      case ZCL_OTA_DL_COMPLETE_CALLBACK:
        if (pMsg->hdr.status == ZSuccess)
        {
          // Reset the CRC Shadow and reboot.  The bootloader will see the
          // CRC shadow has been cleared and switch to the new image
          HalOTAInvRC();
          SystemReset();
        }
        else
        {
          // slow the poll rate back down.
          RxOnIdle = FALSE;
          ZMacSetReq( ZMacRxOnIdle, &RxOnIdle );
          NLME_SetPollRate(DEVICE_POLL_RATE);
        }
        break;
    
      default:
        break;
      }
    }
    #endif // defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    
    /****************************************************************************
    ****************************************************************************/
    
    
    

  • Try to set a breakpoint at zcl_ProcessMessageMSG in zcl_event_loop() to see if it stops there when you send ZCL read attribute command. By the way, I see you send ZCL read attribute command using broadcasting and this might be the problem. Can you change it to unicast to see if the problem is solved?

  • hi;

    I did what you say but problem did not solve.

    I use TI sample Sw and sample Light codes with unicast addressing. when SW1 is pressed,the read command sent to Light but program did not jump to zclLight_ProcessIncomingMsg function.

    /**************************************************************************************************
      Filename:       zcl_LIGHT.c
      Revised:        $Date: 2014-10-24 16:04:46 -0700 (Fri, 24 Oct 2014) $
      Revision:       $Revision: 40796 $
    
    
      Description:    Zigbee Cluster Library - sample device application.
    
    
      Copyright 2006-2014 Texas Instruments Incorporated. All rights reserved.
    
      IMPORTANT: Your use of this Software is limited to those specific rights
      granted under the terms of a software license agreement between the user
      who downloaded the software, his/her employer (which must be your employer)
      and Texas Instruments Incorporated (the "License").  You may not use this
      Software unless you agree to abide by the terms of the License. The License
      limits your use, and you acknowledge, that the Software may not be modified,
      copied or distributed unless embedded on a Texas Instruments microcontroller
      or used solely and exclusively in conjunction with a Texas Instruments radio
      frequency transceiver, which is integrated into your product.  Other than for
      the foregoing purpose, you may not use, reproduce, copy, prepare derivative
      works of, modify, distribute, perform, display or sell this Software and/or
      its documentation for any purpose.
    
      YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
      PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
      INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
      NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
      TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
      NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
      LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
      INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
      OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
      OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
      (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
    
      Should you have any questions regarding your right to use this Software,
      contact Texas Instruments Incorporated at www.TI.com.
    **************************************************************************************************/
    
    /*********************************************************************
      This application implements a ZigBee HA 1.2 Light. It can be configured as an
      On/Off light, or as a dimmable light. The following flags must be defined in
      the compiler's pre-defined symbols.
    
      ZCL_ON_OFF
      ZCL_LEVEL_CTRL    (only if dimming functionality desired)
      HOLD_AUTO_START
      ZCL_EZMODE
    
      This device supports all mandatory and optional commands/attributes for the
      OnOff (0x0006) and LevelControl (0x0008) clusters.
    
      SCREEN MODES
      ----------------------------------------
      Main:
        - SW1: Toggle local light
        - SW2: Invoke EZMode
        - SW4: Enable/Disable local permit join
        - SW5: Go to Help screen
      ----------------------------------------
    *********************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    #include "ZComDef.h"
    #include "OSAL.h"
    #include "AF.h"
    #include "ZDApp.h"
    #include "ZDObject.h"
    #include "MT_SYS.h"
    
    #include "nwk_util.h"
    
    #include "zcl.h"
    #include "zcl_general.h"
    #include "zcl_ha.h"
    #include "zcl_ezmode.h"
    #include "zcl_diagnostic.h"
    
    #include "zcl_light.h"
    
    #include "onboard.h"
    
    /* HAL */
    #include "hal_lcd.h"
    #include "hal_led.h"
    #include "hal_key.h"
    
    #if ( defined (ZGP_DEVICE_TARGET) || defined (ZGP_DEVICE_TARGETPLUS) \
          || defined (ZGP_DEVICE_COMBO) || defined (ZGP_DEVICE_COMBO_MIN) )
    #include "zgp_translationtable.h"
      #if (SUPPORTED_S_FEATURE(SUPP_ZGP_FEATURE_TRANSLATION_TABLE))
        #define ZGP_AUTO_TT
      #endif
    #endif
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    #include "math.h"
    #include "hal_timer.h"
    #endif
    
    #include "NLMEDE.h"
    
    /*********************************************************************
     * MACROS
     */
    
    /*********************************************************************
     * CONSTANTS
     */
    #if (defined HAL_BOARD_ZLIGHT)
    #define LEVEL_MAX                 0xFE
    #define LEVEL_MIN                 0x0
    #define GAMMA_VALUE               2
    #define PWM_FULL_DUTY_CYCLE       1000
    #elif (defined HAL_PWM)
    #define LEVEL_MAX                 0xFE
    #define LEVEL_MIN                 0x0
    #define GAMMA_VALUE               2
    #define PWM_FULL_DUTY_CYCLE       100
    #endif
    
    /*********************************************************************
     * TYPEDEFS
     */
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    byte zclLight_TaskID;
    uint8 zclLightSeqNum;
    
    
    /*********************************************************************
     * GLOBAL FUNCTIONS
     */
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    afAddrType_t zclLight_DstAddr;
    
    #ifdef ZCL_EZMODE
    static void zclLight_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg );
    static void zclLight_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData );
    
    
    // register EZ-Mode with task information (timeout events, callback, etc...)
    static const zclEZMode_RegisterData_t zclLight_RegisterEZModeData =
    {
      &zclLight_TaskID,
      LIGHT_EZMODE_NEXTSTATE_EVT,
      LIGHT_EZMODE_TIMEOUT_EVT,
      &zclLightSeqNum,
      zclLight_EZModeCB
    };
    
    #else
    uint16 bindingInClusters[] =
    {
      ZCL_CLUSTER_ID_GEN_ON_OFF
    #ifdef ZCL_LEVEL_CTRL
      , ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL
    #endif
    };
    #define zclLight_BINDINGLIST (sizeof(bindingInClusters) / sizeof(bindingInClusters[0]))
    
    #endif  // ZCL_EZMODE
    
    // Test Endpoint to allow SYS_APP_MSGs
    static endPointDesc_t LIGHT_TestEp =
    {
      LIGHT_ENDPOINT,
      &zclLight_TaskID,
      (SimpleDescriptionFormat_t *)NULL,  // No Simple description for this test endpoint
      (afNetworkLatencyReq_t)0            // No Network Latency req
    };
    
    uint8 giLightScreenMode = LIGHT_MAINMODE;   // display the main screen mode first
    
    uint8 gPermitDuration = 0;    // permit joining default to disabled
    
    devStates_t zclLight_NwkState = DEV_INIT;
    
    #if ZCL_LEVEL_CTRL
    uint8 zclLight_WithOnOff;       // set to TRUE if state machine should set light on/off
    uint8 zclLight_NewLevel;        // new level when done moving
    bool  zclLight_NewLevelUp;      // is direction to new level up or down?
    int32 zclLight_CurrentLevel32;  // current level, fixed point (e.g. 192.456)
    int32 zclLight_Rate32;          // rate in units, fixed point (e.g. 16.123)
    uint8 zclLight_LevelLastLevel;  // to save the Current Level before the light was turned OFF
    #endif
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    static void zclLight_HandleKeys( byte shift, byte keys );
    static void zclLight_BasicResetCB( void );
    static void zclLight_IdentifyCB( zclIdentify_t *pCmd );
    static void zclLight_IdentifyQueryRspCB( zclIdentifyQueryRsp_t *pRsp );
    static void zclLight_OnOffCB( uint8 cmd );
    static void zclLight_ProcessIdentifyTimeChange( void );
    #ifdef ZCL_LEVEL_CTRL
    static void zclLight_LevelControlMoveToLevelCB( zclLCMoveToLevel_t *pCmd );
    static void zclLight_LevelControlMoveCB( zclLCMove_t *pCmd );
    static void zclLight_LevelControlStepCB( zclLCStep_t *pCmd );
    static void zclLight_LevelControlStopCB( void );
    static void zclLight_DefaultMove( void );
    static uint32 zclLight_TimeRateHelper( uint8 newLevel );
    static uint16 zclLight_GetTime ( uint8 level, uint16 time );
    static void zclLight_MoveBasedOnRate( uint8 newLevel, uint32 rate );
    static void zclLight_MoveBasedOnTime( uint8 newLevel, uint16 time );
    static void zclLight_AdjustLightLevel( void );
    #endif
    
    // app display functions
    static void zclLight_LcdDisplayUpdate( void );
    #ifdef LCD_SUPPORTED
    static void zclLight_LcdDisplayMainMode( void );
    static void zclLight_LcdDisplayHelpMode( void );
    #endif
    static void zclLight_DisplayLight( void );
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    void zclLight_UpdateLampLevel( uint8 level );
    #endif
    
    // Functions to process ZCL Foundation incoming Command/Response messages
    static void zclLight_ProcessIncomingMsg( zclIncomingMsg_t *msg );
    #ifdef ZCL_READ
    static uint8 zclLight_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    #ifdef ZCL_WRITE
    static uint8 zclLight_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    static uint8 zclLight_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg );
    #ifdef ZCL_DISCOVER
    static uint8 zclLight_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclLight_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclLight_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    
    /*********************************************************************
     * STATUS STRINGS
     */
    #ifdef LCD_SUPPORTED
    const char sDeviceName[]   = "  Sample Light";
    const char sClearLine[]    = " ";
    const char sSwLight[]      = "SW1: ToggleLight";  // 16 chars max
    const char sSwEZMode[]     = "SW2: EZ-Mode";
    char sSwHelp[]             = "SW5: Help       ";  // last character is * if NWK open
    const char sLightOn[]      = "    LIGHT ON ";
    const char sLightOff[]     = "    LIGHT OFF";
     #if ZCL_LEVEL_CTRL
     char sLightLevel[]        = "    LEVEL ###"; // displays level 1-254
     #endif
    #endif
    
    /*********************************************************************
     * ZCL General Profile Callback table
     */
    static zclGeneral_AppCallbacks_t zclLight_CmdCallbacks =
    {
      zclLight_BasicResetCB,            // Basic Cluster Reset command
      zclLight_IdentifyCB,              // Identify command
    #ifdef ZCL_EZMODE
      NULL,                                   // Identify EZ-Mode Invoke command
      NULL,                                   // Identify Update Commission State command
    #endif
      NULL,                                   // Identify Trigger Effect command
      zclLight_IdentifyQueryRspCB,      // Identify Query Response command
      zclLight_OnOffCB,                 // On/Off cluster commands
      NULL,                                   // On/Off cluster enhanced command Off with Effect
      NULL,                                   // On/Off cluster enhanced command On with Recall Global Scene
      NULL,                                   // On/Off cluster enhanced command On with Timed Off
    #ifdef ZCL_LEVEL_CTRL
      zclLight_LevelControlMoveToLevelCB, // Level Control Move to Level command
      zclLight_LevelControlMoveCB,        // Level Control Move command
      zclLight_LevelControlStepCB,        // Level Control Step command
      zclLight_LevelControlStopCB,        // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPS
      NULL,                                   // Group Response commands
    #endif
    #ifdef ZCL_SCENES
      NULL,                                  // Scene Store Request command
      NULL,                                  // Scene Recall Request command
      NULL,                                  // Scene Response command
    #endif
    #ifdef ZCL_ALARMS
      NULL,                                  // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXT
      NULL,                                  // Get Event Log command
      NULL,                                  // Publish Event Log command
    #endif
      NULL,                                  // RSSI Location command
      NULL                                   // RSSI Location Response command
    };
    
    /*********************************************************************
     * @fn          zclLight_Init
     *
     * @brief       Initialization function for the zclGeneral layer.
     *
     * @param       none
     *
     * @return      none
     */
    void zclLight_Init( byte task_id )
    {
      zclLight_TaskID = task_id;
    
      // Set destination address to indirect
      zclLight_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
      zclLight_DstAddr.endPoint = 0;
      zclLight_DstAddr.addr.shortAddr = 0;
    
      // This app is part of the Home Automation Profile
      zclHA_Init( &zclLight_SimpleDesc );
    
      // Register the ZCL General Cluster Library callback functions
      zclGeneral_RegisterCmdCallbacks( LIGHT_ENDPOINT, &zclLight_CmdCallbacks );
    
      // Register the application's attribute list
      zcl_registerAttrList( LIGHT_ENDPOINT, zclLight_NumAttributes, zclLight_Attrs );
    
      // Register the Application to receive the unprocessed Foundation command/response messages
      zcl_registerForMsg( zclLight_TaskID );
    
    #ifdef ZCL_DISCOVER
      // Register the application's command list
      zcl_registerCmdList( LIGHT_ENDPOINT, zclCmdsArraySize, zclLight_Cmds );
    #endif
    
      // Register for all key events - This app will handle all key events
      RegisterForKeys( zclLight_TaskID );
    
      // Register for a test endpoint
      afRegister( &LIGHT_TestEp );
    
    #ifdef ZCL_EZMODE
      // Register EZ-Mode
      zcl_RegisterEZMode( &zclLight_RegisterEZModeData );
    
      // Register with the ZDO to receive Match Descriptor Responses
      ZDO_RegisterForZDOMsg(task_id, Match_Desc_rsp);
    #endif
    
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
      HalTimer1Init( 0 );
      halTimer1SetChannelDuty( WHITE_LED, 0 );
      halTimer1SetChannelDuty( RED_LED, 0 );
      halTimer1SetChannelDuty( BLUE_LED, 0 );
      halTimer1SetChannelDuty( GREEN_LED, 0 );
    
      // find if we are already on a network from NV_RESTORE
      uint8 state;
      NLME_GetRequest( nwkNwkState, 0, &state );
    
      if ( state < NWK_ENDDEVICE )
      {
        // Start EZMode on Start up to avoid button press
        osal_start_timerEx( zclLight_TaskID, LIGHT_START_EZMODE_EVT, 500 );
      }
    #if ZCL_LEVEL_CTRL
      zclLight_DefaultMove();
    #endif
    #endif // #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    
    #ifdef ZCL_DIAGNOSTIC
      // Register the application's callback function to read/write attribute data.
      // This is only required when the attribute data format is unknown to ZCL.
      zcl_registerReadWriteCB( LIGHT_ENDPOINT, zclDiagnostic_ReadWriteAttrCB, NULL );
    
      if ( zclDiagnostic_InitStats() == ZSuccess )
      {
        // Here the user could start the timer to save Diagnostics to NV
      }
    #endif
    
    #ifdef LCD_SUPPORTED
      HalLcdWriteString ( (char *)sDeviceName, HAL_LCD_LINE_3 );
    #endif  // LCD_SUPPORTED
    
    #ifdef ZGP_AUTO_TT
      zgpTranslationTable_RegisterEP ( &zclLight_SimpleDesc );
    #endif
    }
    
    /*********************************************************************
     * @fn          zclSample_event_loop
     *
     * @brief       Event Loop Processor for zclGeneral.
     *
     * @param       none
     *
     * @return      none
     */
    uint16 zclLight_event_loop( uint8 task_id, uint16 events )
    {
      afIncomingMSGPacket_t *MSGpkt;
    
      (void)task_id;  // Intentionally unreferenced parameter
    
      if ( events & SYS_EVENT_MSG )
      {
        while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( zclLight_TaskID )) )
        {
          switch ( MSGpkt->hdr.event )
          {
    #ifdef ZCL_EZMODE
            case ZDO_CB_MSG:
              zclLight_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
              break;
    #endif
            case ZCL_INCOMING_MSG:
              // Incoming ZCL Foundation command/response messages
              zclLight_ProcessIncomingMsg( (zclIncomingMsg_t *)MSGpkt );
              break;
    
            case KEY_CHANGE:
              zclLight_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
              break;
    
            case ZDO_STATE_CHANGE:
              zclLight_NwkState = (devStates_t)(MSGpkt->hdr.status);
    
              // now on the network
              if ( (zclLight_NwkState == DEV_ZB_COORD) ||
                   (zclLight_NwkState == DEV_ROUTER)   ||
                   (zclLight_NwkState == DEV_END_DEVICE) )
              {
                giLightScreenMode = LIGHT_MAINMODE;
                zclLight_LcdDisplayUpdate();
    #ifdef ZCL_EZMODE
                zcl_EZModeAction( EZMODE_ACTION_NETWORK_STARTED, NULL );
    #endif // ZCL_EZMODE
              }
              break;
    
            default:
              break;
          }
    
          // Release the memory
          osal_msg_deallocate( (uint8 *)MSGpkt );
        }
    
        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
      }
    
      if ( events & LIGHT_IDENTIFY_TIMEOUT_EVT )
      {
        if ( zclLight_IdentifyTime > 0 )
          zclLight_IdentifyTime--;
        zclLight_ProcessIdentifyTimeChange();
    
        return ( events ^ LIGHT_IDENTIFY_TIMEOUT_EVT );
      }
    
      if ( events & LIGHT_MAIN_SCREEN_EVT )
      {
        giLightScreenMode = LIGHT_MAINMODE;
        zclLight_LcdDisplayUpdate();
    
        return ( events ^ LIGHT_MAIN_SCREEN_EVT );
      }
    
    #ifdef ZCL_EZMODE
    #if (defined HAL_BOARD_ZLIGHT)
      // event to start EZMode on startup with a delay
      if ( events & LIGHT_START_EZMODE_EVT )
      {
        // Invoke EZ-Mode
        zclEZMode_InvokeData_t ezModeData;
    
        // Invoke EZ-Mode
        ezModeData.endpoint = LIGHT_ENDPOINT; // endpoint on which to invoke EZ-Mode
        if ( (zclLight_NwkState == DEV_ZB_COORD) ||
             (zclLight_NwkState == DEV_ROUTER)   ||
             (zclLight_NwkState == DEV_END_DEVICE) )
        {
          ezModeData.onNetwork = TRUE;      // node is already on the network
        }
        else
        {
          ezModeData.onNetwork = FALSE;     // node is not yet on the network
        }
        ezModeData.initiator = FALSE;          // OnOffLight is a target
        ezModeData.numActiveOutClusters = 0;
        ezModeData.pActiveOutClusterIDs = NULL;
        ezModeData.numActiveInClusters = 0;
        ezModeData.pActiveOutClusterIDs = NULL;
        zcl_InvokeEZMode( &ezModeData );
    
        return ( events ^ LIGHT_START_EZMODE_EVT );
      }
    #endif // #if (defined HAL_BOARD_ZLIGHT)
    
      // going on to next state
      if ( events & LIGHT_EZMODE_NEXTSTATE_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_PROCESS, NULL );   // going on to next state
        return ( events ^ LIGHT_EZMODE_NEXTSTATE_EVT );
      }
    
      // the overall EZMode timer expired, so we timed out
      if ( events & LIGHT_EZMODE_TIMEOUT_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_TIMED_OUT, NULL ); // EZ-Mode timed out
        return ( events ^ LIGHT_EZMODE_TIMEOUT_EVT );
      }
    #endif // ZLC_EZMODE
    
    #ifdef ZCL_LEVEL_CTRL
      if ( events & LIGHT_LEVEL_CTRL_EVT )
      {
        zclLight_AdjustLightLevel();
        return ( events ^ LIGHT_LEVEL_CTRL_EVT );
      }
    #endif
    
      // Discard unknown events
      return 0;
    }
    
    /*********************************************************************
     * @fn      zclLight_HandleKeys
     *
     * @brief   Handles all key events for this device.
     *
     * @param   shift - true if in shift/alt.
     * @param   keys - bit field for key events. Valid entries:
     *                 HAL_KEY_SW_5
     *                 HAL_KEY_SW_4
     *                 HAL_KEY_SW_2
     *                 HAL_KEY_SW_1
     *
     * @return  none
     */
    static void zclLight_HandleKeys( byte shift, byte keys )
    {
      if ( keys & HAL_KEY_SW_1 )
      {
        giLightScreenMode = LIGHT_MAINMODE;
    
        // toggle local light immediately
        zclLight_OnOff = zclLight_OnOff ? LIGHT_OFF : LIGHT_ON;
    #ifdef ZCL_LEVEL_CTRL
        zclLight_LevelCurrentLevel = zclLight_OnOff ? zclLight_LevelOnLevel : ATTR_LEVEL_MIN_LEVEL;
    #endif
      }
    
      if ( keys & HAL_KEY_SW_2 )
      {
    #if (defined HAL_BOARD_ZLIGHT)
    
        zclLight_BasicResetCB();
    
    #else
    
        giLightScreenMode = LIGHT_MAINMODE;
    
    #ifdef ZCL_EZMODE
        {
          // Invoke EZ-Mode
          zclEZMode_InvokeData_t ezModeData;
    
          // Invoke EZ-Mode
          ezModeData.endpoint = LIGHT_ENDPOINT; // endpoint on which to invoke EZ-Mode
          if ( (zclLight_NwkState == DEV_ZB_COORD) ||
              (zclLight_NwkState == DEV_ROUTER)   ||
                (zclLight_NwkState == DEV_END_DEVICE) )
          {
            ezModeData.onNetwork = TRUE;      // node is already on the network
          }
          else
          {
            ezModeData.onNetwork = FALSE;     // node is not yet on the network
          }
          ezModeData.initiator = FALSE;          // OnOffLight is a target
          ezModeData.numActiveOutClusters = 0;
          ezModeData.pActiveOutClusterIDs = NULL;
          ezModeData.numActiveInClusters = 0;
          ezModeData.pActiveOutClusterIDs = NULL;
          zcl_InvokeEZMode( &ezModeData );
        }
    
    #else // NOT EZ-Mode
        {
          zAddrType_t dstAddr;
          HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
    
          // Initiate an End Device Bind Request, this bind request will
          // only use a cluster list that is important to binding.
          dstAddr.addrMode = afAddr16Bit;
          dstAddr.addr.shortAddr = 0;   // Coordinator makes the match
          ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
                               LIGHT_ENDPOINT,
                               ZCL_HA_PROFILE_ID,
                               zclLight_BINDINGLIST, bindingInClusters,
                               0, NULL,   // No Outgoing clusters to bind
                               TRUE );
        }
    #endif // ZCL_EZMODE
    #endif // HAL_BOARD_ZLIGHT
      }
    
      if ( keys & HAL_KEY_SW_3 )
      {
        NLME_SendNetworkStatus( zclLight_DstAddr.addr.shortAddr,
                           NLME_GetShortAddr(), NWKSTAT_NONTREE_LINK_FAILURE, FALSE );
      }
    
      if ( keys & HAL_KEY_SW_4 )
      {
        giLightScreenMode = LIGHT_MAINMODE;
    
        if ( ( zclLight_NwkState == DEV_ZB_COORD ) ||
              ( zclLight_NwkState == DEV_ROUTER ) )
        {
          zAddrType_t tmpAddr;
    
          tmpAddr.addrMode = Addr16Bit;
          tmpAddr.addr.shortAddr = NLME_GetShortAddr();
    
          // toggle permit join
          gPermitDuration = gPermitDuration ? 0 : 0xff;
    
          // Trust Center significance is always true
          ZDP_MgmtPermitJoinReq( &tmpAddr, gPermitDuration, TRUE, FALSE );
        }
      }
    
      // Shift F5 does a Basic Reset (factory defaults)
      if ( shift && ( keys & HAL_KEY_SW_5 ) )
      {
        zclLight_BasicResetCB();
      }
      else if ( keys & HAL_KEY_SW_5 )
      {
        giLightScreenMode = giLightScreenMode ? LIGHT_MAINMODE : LIGHT_HELPMODE;
      }
    
      // update the display, including the light
      zclLight_LcdDisplayUpdate();
    }
    
    /*********************************************************************
     * @fn      zclLight_LcdDisplayUpdate
     *
     * @brief   Called to update the LCD display.
     *
     * @param   none
     *
     * @return  none
     */
    void zclLight_LcdDisplayUpdate( void )
    {
    #ifdef LCD_SUPPORTED
      if ( giLightScreenMode == LIGHT_HELPMODE )
      {
        zclLight_LcdDisplayHelpMode();
      }
      else
      {
        zclLight_LcdDisplayMainMode();
      }
    #endif
    
      zclLight_DisplayLight();
    }
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
    /*********************************************************************
     * @fn      zclLight_UpdateLampLevel
     *
     * @brief   Update lamp level output with gamma compensation
     *
     * @param   level
     *
     * @return  none
     */
    void zclLight_UpdateLampLevel( uint8 level )
    
    {
      uint16 gammaCorrectedLevel;
    
      // gamma correct the level
      gammaCorrectedLevel = (uint16) ( pow( ( (float)level / LEVEL_MAX ), (float)GAMMA_VALUE ) * (float)LEVEL_MAX);
    
      halTimer1SetChannelDuty(WHITE_LED, (uint16)(((uint32)gammaCorrectedLevel*PWM_FULL_DUTY_CYCLE)/LEVEL_MAX) );
    }
    #endif
    
    /*********************************************************************
     * @fn      zclLight_DisplayLight
     *
     * @brief   Displays current state of light on LED and also on main display if supported.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight_DisplayLight( void )
    {
      // set the LED1 based on light (on or off)
      if ( zclLight_OnOff == LIGHT_ON )
      {
        HalLedSet ( HAL_LED_1, HAL_LED_MODE_ON );
      }
      else
      {
        HalLedSet ( HAL_LED_1, HAL_LED_MODE_OFF );
      }
    
    #ifdef LCD_SUPPORTED
      if (giLightScreenMode == LIGHT_MAINMODE)
      {
    #ifdef ZCL_LEVEL_CTRL
        // display current light level
        if ( ( zclLight_LevelCurrentLevel == ATTR_LEVEL_MIN_LEVEL ) &&
             ( zclLight_OnOff == LIGHT_OFF ) )
        {
          HalLcdWriteString( (char *)sLightOff, HAL_LCD_LINE_2 );
        }
        else if ( ( zclLight_LevelCurrentLevel >= ATTR_LEVEL_MAX_LEVEL ) ||
                  ( zclLight_LevelCurrentLevel == zclLight_LevelOnLevel ) ||
                   ( ( zclLight_LevelOnLevel == ATTR_LEVEL_ON_LEVEL_NO_EFFECT ) &&
                     ( zclLight_LevelCurrentLevel == zclLight_LevelLastLevel ) ) )
        {
          HalLcdWriteString( (char *)sLightOn, HAL_LCD_LINE_2 );
        }
        else    // "    LEVEL ###"
        {
          zclHA_uint8toa( zclLight_LevelCurrentLevel, &sLightLevel[10] );
          HalLcdWriteString( (char *)sLightLevel, HAL_LCD_LINE_2 );
        }
    #else
        if ( zclLight_OnOff )
        {
          HalLcdWriteString( (char *)sLightOn, HAL_LCD_LINE_2 );
        }
        else
        {
          HalLcdWriteString( (char *)sLightOff, HAL_LCD_LINE_2 );
        }
    #endif // ZCL_LEVEL_CTRL
      }
    #endif // LCD_SUPPORTED
    }
    
    #ifdef LCD_SUPPORTED
    /*********************************************************************
     * @fn      zclLight_LcdDisplayMainMode
     *
     * @brief   Called to display the main screen on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight_LcdDisplayMainMode( void )
    {
      // display line 1 to indicate NWK status
      if ( zclLight_NwkState == DEV_ZB_COORD )
      {
        zclHA_LcdStatusLine1( ZCL_HA_STATUSLINE_ZC );
      }
      else if ( zclLight_NwkState == DEV_ROUTER )
      {
        zclHA_LcdStatusLine1( ZCL_HA_STATUSLINE_ZR );
      }
      else if ( zclLight_NwkState == DEV_END_DEVICE )
      {
        zclHA_LcdStatusLine1( ZCL_HA_STATUSLINE_ZED );
      }
    
      // end of line 3 displays permit join status (*)
      if ( gPermitDuration )
      {
        sSwHelp[15] = '*';
      }
      else
      {
        sSwHelp[15] = ' ';
      }
      HalLcdWriteString( (char *)sSwHelp, HAL_LCD_LINE_3 );
    }
    
    /*********************************************************************
     * @fn      zclLight_LcdDisplayHelpMode
     *
     * @brief   Called to display the SW options on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight_LcdDisplayHelpMode( void )
    {
      HalLcdWriteString( (char *)sSwLight, HAL_LCD_LINE_1 );
      HalLcdWriteString( (char *)sSwEZMode, HAL_LCD_LINE_2 );
      HalLcdWriteString( (char *)sSwHelp, HAL_LCD_LINE_3 );
    }
    #endif  // LCD_SUPPORTED
    
    /*********************************************************************
     * @fn      zclLight_ProcessIdentifyTimeChange
     *
     * @brief   Called to process any change to the IdentifyTime attribute.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight_ProcessIdentifyTimeChange( void )
    {
      if ( zclLight_IdentifyTime > 0 )
      {
        osal_start_timerEx( zclLight_TaskID, LIGHT_IDENTIFY_TIMEOUT_EVT, 1000 );
        HalLedBlink ( HAL_LED_4, 0xFF, HAL_LED_DEFAULT_DUTY_CYCLE, HAL_LED_DEFAULT_FLASH_TIME );
      }
      else
      {
    #ifdef ZCL_EZMODE
        if ( zclLight_IdentifyCommissionState & EZMODE_COMMISSION_OPERATIONAL )
        {
          HalLedSet ( HAL_LED_4, HAL_LED_MODE_ON );
        }
        else
        {
          HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
        }
    #endif
    
        osal_stop_timerEx( zclLight_TaskID, LIGHT_IDENTIFY_TIMEOUT_EVT );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight_BasicResetCB
     *
     * @brief   Callback from the ZCL General Cluster Library
     *          to set all the Basic Cluster attributes to default values.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight_BasicResetCB( void )
    {
      NLME_LeaveReq_t leaveReq;
      // Set every field to 0
      osal_memset( &leaveReq, 0, sizeof( NLME_LeaveReq_t ) );
    
      // This will enable the device to rejoin the network after reset.
      leaveReq.rejoin = TRUE;
    
      // Set the NV startup option to force a "new" join.
      zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );
    
      // Leave the network, and reset afterwards
      if ( NLME_LeaveReq( &leaveReq ) != ZSuccess )
      {
        // Couldn't send out leave; prepare to reset anyway
        ZDApp_LeaveReset( FALSE );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight_IdentifyCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Command for this application.
     *
     * @param   srcAddr - source address and endpoint of the response message
     * @param   identifyTime - the number of seconds to identify yourself
     *
     * @return  none
     */
    static void zclLight_IdentifyCB( zclIdentify_t *pCmd )
    {
      zclLight_IdentifyTime = pCmd->identifyTime;
      zclLight_ProcessIdentifyTimeChange();
    }
    
    /*********************************************************************
     * @fn      zclLight_IdentifyQueryRspCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Query Response Command for this application.
     *
     * @param   srcAddr - requestor's address
     * @param   timeout - number of seconds to identify yourself (valid for query response)
     *
     * @return  none
     */
    static void zclLight_IdentifyQueryRspCB(  zclIdentifyQueryRsp_t *pRsp )
    {
      (void)pRsp;
    #ifdef ZCL_EZMODE
      {
        zclEZMode_ActionData_t data;
        data.pIdentifyQueryRsp = pRsp;
        zcl_EZModeAction ( EZMODE_ACTION_IDENTIFY_QUERY_RSP, &data );
      }
    #endif
    }
    
    /*********************************************************************
     * @fn      zclLight_OnOffCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an On/Off Command for this application.
     *
     * @param   cmd - COMMAND_ON, COMMAND_OFF or COMMAND_TOGGLE
     *
     * @return  none
     */
    static void zclLight_OnOffCB( uint8 cmd )
    {
      afIncomingMSGPacket_t *pPtr = zcl_getRawAFMsg();
    
      zclLight_DstAddr.addr.shortAddr = pPtr->srcAddr.addr.shortAddr;
    
    
      // Turn on the light
      if ( cmd == COMMAND_ON )
      {
        zclLight_OnOff = LIGHT_ON;
      }
      // Turn off the light
      else if ( cmd == COMMAND_OFF )
      {
        zclLight_OnOff = LIGHT_OFF;
      }
      // Toggle the light
      else if ( cmd == COMMAND_TOGGLE )
      {
        if ( zclLight_OnOff == LIGHT_OFF )
        {
          zclLight_OnOff = LIGHT_ON;
        }
        else
        {
          zclLight_OnOff = LIGHT_OFF;
        }
      }
    
    #if ZCL_LEVEL_CTRL
      zclLight_DefaultMove( );
    #endif
    
      // update the display
      zclLight_LcdDisplayUpdate( );
    }
    
    #ifdef ZCL_LEVEL_CTRL
    /*********************************************************************
     * @fn      zclLight_TimeRateHelper
     *
     * @brief   Calculate time based on rate, and startup level state machine
     *
     * @param   newLevel - new level for current level
     *
     * @return  diff (directly), zclLight_CurrentLevel32 and zclLight_NewLevel, zclLight_NewLevelUp
     */
    static uint32 zclLight_TimeRateHelper( uint8 newLevel )
    {
      uint32 diff;
      uint32 newLevel32;
    
      // remember current and new level
      zclLight_NewLevel = newLevel;
      zclLight_CurrentLevel32 = (uint32)1000 * zclLight_LevelCurrentLevel;
    
      // calculate diff
      newLevel32 = (uint32)1000 * newLevel;
      if ( zclLight_LevelCurrentLevel > newLevel )
      {
        diff = zclLight_CurrentLevel32 - newLevel32;
        zclLight_NewLevelUp = FALSE;  // moving down
      }
      else
      {
        diff = newLevel32 - zclLight_CurrentLevel32;
        zclLight_NewLevelUp = TRUE;   // moving up
      }
    
      return ( diff );
    }
    
    /*********************************************************************
     * @fn      zclLight_MoveBasedOnRate
     *
     * @brief   Calculate time based on rate, and startup level state machine
     *
     * @param   newLevel - new level for current level
     * @param   rate16   - fixed point rate (e.g. 16.123)
     *
     * @return  none
     */
    static void zclLight_MoveBasedOnRate( uint8 newLevel, uint32 rate )
    {
      uint32 diff;
    
      // determine how much time (in 10ths of seconds) based on the difference and rate
      zclLight_Rate32 = rate;
      diff = zclLight_TimeRateHelper( newLevel );
      zclLight_LevelRemainingTime = diff / rate;
      if ( !zclLight_LevelRemainingTime )
      {
        zclLight_LevelRemainingTime = 1;
      }
    
      osal_start_timerEx( zclLight_TaskID, LIGHT_LEVEL_CTRL_EVT, 100 );
    }
    
    /*********************************************************************
     * @fn      zclLight_MoveBasedOnTime
     *
     * @brief   Calculate rate based on time, and startup level state machine
     *
     * @param   newLevel  - new level for current level
     * @param   time      - in 10ths of seconds
     *
     * @return  none
     */
    static void zclLight_MoveBasedOnTime( uint8 newLevel, uint16 time )
    {
      uint16 diff;
    
      // determine rate (in units) based on difference and time
      diff = zclLight_TimeRateHelper( newLevel );
      zclLight_LevelRemainingTime = zclLight_GetTime( newLevel, time );
      zclLight_Rate32 = diff / time;
    
      osal_start_timerEx( zclLight_TaskID, LIGHT_LEVEL_CTRL_EVT, 100 );
    }
    
    /*********************************************************************
     * @fn      zclLight_GetTime
     *
     * @brief   Determine amount of time that MoveXXX will take to complete.
     *
     * @param   level = new level to move to
     *          time  = 0xffff=default, or 0x0000-n amount of time in tenths of seconds.
     *
     * @return  none
     */
    static uint16 zclLight_GetTime( uint8 level, uint16 time )
    {
      // there is a hiearchy of the amount of time to use for transistioning
      // check each one in turn. If none of defaults are set, then use fastest
      // time possible.
      if ( time == 0xFFFF )
      {
        // use On or Off Transition Time if set (not 0xffff)
        if ( zclLight_OnOff == LIGHT_ON )
        {
          time = zclLight_LevelOffTransitionTime;
        }
        else
        {
          time = zclLight_LevelOnTransitionTime;
        }
    
        // else use OnOffTransitionTime if set (not 0xffff)
        if ( time == 0xFFFF )
        {
          time = zclLight_LevelOnOffTransitionTime;
        }
    
        // else as fast as possible
        if ( time == 0xFFFF )
        {
          time = 1;
        }
      }
    
      if ( !time )
      {
        time = 1; // as fast as possible
      }
    
      return ( time );
    }
    
    /*********************************************************************
     * @fn      zclLight_DefaultMove
     *
     * @brief   We were turned on/off. Use default time to move to on or off.
     *
     * @param   zclLight_OnOff - must be set prior to calling this function.
     *
     * @return  none
     */
    static void zclLight_DefaultMove( void )
    {
      uint8  newLevel;
      uint32 rate;      // fixed point decimal (3 places, eg. 16.345)
      uint16 time;
    
      // if moving to on position, move to on level
      if ( zclLight_OnOff )
      {
        if ( zclLight_LevelOnLevel == ATTR_LEVEL_ON_LEVEL_NO_EFFECT )
        {
          // The last Level (before going OFF) should be used)
          newLevel = zclLight_LevelLastLevel;
        }
        else
        {
          newLevel = zclLight_LevelOnLevel;
        }
    
        time = zclLight_LevelOnTransitionTime;
      }
      else
      {
        newLevel = ATTR_LEVEL_MIN_LEVEL;
    
        if ( zclLight_LevelOnLevel == ATTR_LEVEL_ON_LEVEL_NO_EFFECT )
        {
          // Save the current Level before going OFF to use it when the light turns ON
          // it should be back to this level
          zclLight_LevelLastLevel = zclLight_LevelCurrentLevel;
        }
    
        time = zclLight_LevelOffTransitionTime;
      }
    
      // else use OnOffTransitionTime if set (not 0xffff)
      if ( time == 0xFFFF )
      {
        time = zclLight_LevelOnOffTransitionTime;
      }
    
      // else as fast as possible
      if ( time == 0xFFFF )
      {
        time = 1;
      }
    
      // calculate rate based on time (int 10ths) for full transition (1-254)
      rate = 255000 / time;    // units per tick, fixed point, 3 decimal places (e.g. 8500 = 8.5 units per tick)
    
      // start up state machine.
      zclLight_WithOnOff = TRUE;
      zclLight_MoveBasedOnRate( newLevel, rate );
    }
    
    /*********************************************************************
     * @fn      zclLight_AdjustLightLevel
     *
     * @brief   Called each 10th of a second while state machine running
     *
     * @param   none
     *
     * @return  none
     */
    static void zclLight_AdjustLightLevel( void )
    {
      // one tick (10th of a second) less
      if ( zclLight_LevelRemainingTime )
      {
        --zclLight_LevelRemainingTime;
      }
    
      // no time left, done
      if ( zclLight_LevelRemainingTime == 0)
      {
        zclLight_LevelCurrentLevel = zclLight_NewLevel;
      }
    
      // still time left, keep increment/decrementing
      else
      {
        if ( zclLight_NewLevelUp )
        {
          zclLight_CurrentLevel32 += zclLight_Rate32;
        }
        else
        {
          zclLight_CurrentLevel32 -= zclLight_Rate32;
        }
        zclLight_LevelCurrentLevel = (uint8)( zclLight_CurrentLevel32 / 1000 );
      }
    
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
      zclLight_UpdateLampLevel(zclLight_LevelCurrentLevel);
    #endif
    
      // also affect on/off
      if ( zclLight_WithOnOff )
      {
        if ( zclLight_LevelCurrentLevel > ATTR_LEVEL_MIN_LEVEL )
        {
          zclLight_OnOff = LIGHT_ON;
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
          ENABLE_LAMP;
    #endif
        }
        else
        {
          zclLight_OnOff = LIGHT_OFF;
    #if (defined HAL_BOARD_ZLIGHT) || (defined HAL_PWM)
          DISABLE_LAMP;
    #endif
        }
      }
    
      // display light level as we go
      zclLight_DisplayLight( );
    
      // keep ticking away
      if ( zclLight_LevelRemainingTime )
      {
        osal_start_timerEx( zclLight_TaskID, LIGHT_LEVEL_CTRL_EVT, 100 );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight_LevelControlMoveToLevelCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received a LevelControlMoveToLevel Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight_LevelControlMoveToLevelCB( zclLCMoveToLevel_t *pCmd )
    {
      zclLight_WithOnOff = pCmd->withOnOff;
      zclLight_MoveBasedOnTime( pCmd->level, pCmd->transitionTime );
    }
    
    /*********************************************************************
     * @fn      zclLight_LevelControlMoveCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received a LevelControlMove Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight_LevelControlMoveCB( zclLCMove_t *pCmd )
    {
      uint8 newLevel;
      uint32 rate;
    
      // convert rate from units per second to units per tick (10ths of seconds)
      // and move at that right up or down
      zclLight_WithOnOff = pCmd->withOnOff;
    
      if ( pCmd->moveMode == LEVEL_MOVE_UP )
      {
        newLevel = ATTR_LEVEL_MAX_LEVEL;  // fully on
      }
      else
      {
        newLevel = ATTR_LEVEL_MIN_LEVEL; // fully off
      }
    
      rate = (uint32)100 * pCmd->rate;
      zclLight_MoveBasedOnRate( newLevel, rate );
    }
    
    /*********************************************************************
     * @fn      zclLight_LevelControlStepCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an On/Off Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight_LevelControlStepCB( zclLCStep_t *pCmd )
    {
      uint8 newLevel;
    
      // determine new level, but don't exceed boundaries
      if ( pCmd->stepMode == LEVEL_MOVE_UP )
      {
        if ( (uint16)zclLight_LevelCurrentLevel + pCmd->amount > ATTR_LEVEL_MAX_LEVEL )
        {
          newLevel = ATTR_LEVEL_MAX_LEVEL;
        }
        else
        {
          newLevel = zclLight_LevelCurrentLevel + pCmd->amount;
        }
      }
      else
      {
        if ( pCmd->amount >= zclLight_LevelCurrentLevel )
        {
          newLevel = ATTR_LEVEL_MIN_LEVEL;
        }
        else
        {
          newLevel = zclLight_LevelCurrentLevel - pCmd->amount;
        }
      }
    
      // move to the new level
      zclLight_WithOnOff = pCmd->withOnOff;
      zclLight_MoveBasedOnTime( newLevel, pCmd->transitionTime );
    }
    
    /*********************************************************************
     * @fn      zclLight_LevelControlStopCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Level Control Stop Command for this application.
     *
     * @param   pCmd - ZigBee command parameters
     *
     * @return  none
     */
    static void zclLight_LevelControlStopCB( void )
    {
      // stop immediately
      osal_stop_timerEx( zclLight_TaskID, LIGHT_LEVEL_CTRL_EVT );
      zclLight_LevelRemainingTime = 0;
    }
    #endif
    
    /******************************************************************************
     *
     *  Functions for processing ZCL Foundation incoming Command/Response messages
     *
     *****************************************************************************/
    
    /*********************************************************************
     * @fn      zclLight_ProcessIncomingMsg
     *
     * @brief   Process ZCL Foundation incoming message
     *
     * @param   pInMsg - pointer to the received message
     *
     * @return  none
     */
    static void zclLight_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg )
    {
      HAL_TOGGLE_LED2();
    
      switch ( pInMsg->zclHdr.commandID )
      {
        
    #ifdef ZCL_READ
        case ZCL_CMD_READ_RSP:
          zclLight_ProcessInReadRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_WRITE
        case ZCL_CMD_WRITE_RSP:
          zclLight_ProcessInWriteRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_REPORT
        // Attribute Reporting implementation should be added here
        case ZCL_CMD_CONFIG_REPORT:
          // zclLight_ProcessInConfigReportCmd( pInMsg );
          break;
    
        case ZCL_CMD_CONFIG_REPORT_RSP:
          // zclLight_ProcessInConfigReportRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG:
          // zclLight_ProcessInReadReportCfgCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG_RSP:
          // zclLight_ProcessInReadReportCfgRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_REPORT:
          // zclLight_ProcessInReportCmd( pInMsg );
          break;
    #endif
        case ZCL_CMD_DEFAULT_RSP:
          zclLight_ProcessInDefaultRspCmd( pInMsg );
          break;
    #ifdef ZCL_DISCOVER
        case ZCL_CMD_DISCOVER_CMDS_RECEIVED_RSP:
          zclLight_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_CMDS_GEN_RSP:
          zclLight_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_RSP:
          zclLight_ProcessInDiscAttrsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_EXT_RSP:
          zclLight_ProcessInDiscAttrsExtRspCmd( pInMsg );
          break;
    #endif
        default:
          break;
      }
    
      if ( pInMsg->attrCmd )
        osal_mem_free( pInMsg->attrCmd );
    }
    
    #ifdef ZCL_READ
    /*********************************************************************
     * @fn      zclLight_ProcessInReadRspCmd
     *
     * @brief   Process the "Profile" Read Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclReadRspCmd_t *readRspCmd;
      uint8 i;
    
      readRspCmd = (zclReadRspCmd_t *)pInMsg->attrCmd;
      for (i = 0; i < readRspCmd->numAttr; i++)
      {
        // Notify the originator of the results of the original read attributes
        // attempt and, for each successfull request, the value of the requested
        // attribute
      }
    
      return ( TRUE );
    }
    #endif // ZCL_READ
    
    #ifdef ZCL_WRITE
    /*********************************************************************
     * @fn      zclLight_ProcessInWriteRspCmd
     *
     * @brief   Process the "Profile" Write Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclWriteRspCmd_t *writeRspCmd;
      uint8 i;
    
      writeRspCmd = (zclWriteRspCmd_t *)pInMsg->attrCmd;
      for ( i = 0; i < writeRspCmd->numAttr; i++ )
      {
        // Notify the device of the results of the its original write attributes
        // command.
      }
    
      return ( TRUE );
    }
    #endif // ZCL_WRITE
    
    /*********************************************************************
     * @fn      zclLight_ProcessInDefaultRspCmd
     *
     * @brief   Process the "Profile" Default Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg )
    {
      // zclDefaultRspCmd_t *defaultRspCmd = (zclDefaultRspCmd_t *)pInMsg->attrCmd;
    
      // Device is notified of the Default Response command.
      (void)pInMsg;
    
      return ( TRUE );
    }
    
    #ifdef ZCL_DISCOVER
    /*********************************************************************
     * @fn      zclLight_ProcessInDiscCmdsRspCmd
     *
     * @brief   Process the Discover Commands Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverCmdsCmdRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverCmdsCmdRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numCmd; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return ( TRUE );
    }
    
    /*********************************************************************
     * @fn      zclLight_ProcessInDiscAttrsRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsRspCmd_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsRspCmd_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return ( TRUE );
    }
    
    /*********************************************************************
     * @fn      zclLight_ProcessInDiscAttrsExtRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Extended Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclLight_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsExtRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsExtRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return ( TRUE );
    }
    #endif // ZCL_DISCOVER
    
    #if ZCL_EZMODE
    /*********************************************************************
     * @fn      zclLight_ProcessZDOMsgs
     *
     * @brief   Called when this node receives a ZDO/ZDP response.
     *
     * @param   none
     *
     * @return  status
     */
    static void zclLight_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg )
    {
      zclEZMode_ActionData_t data;
      ZDO_MatchDescRsp_t *pMatchDescRsp;
    
      // Let EZ-Mode know of the Simple Descriptor Response
      if ( pMsg->clusterID == Match_Desc_rsp )
      {
        pMatchDescRsp = ZDO_ParseEPListRsp( pMsg );
        data.pMatchDescRsp = pMatchDescRsp;
        zcl_EZModeAction( EZMODE_ACTION_MATCH_DESC_RSP, &data );
        osal_mem_free( pMatchDescRsp );
      }
    }
    
    /*********************************************************************
     * @fn      zclLight_EZModeCB
     *
     * @brief   The Application is informed of events. This can be used to show on the UI what is
    *           going on during EZ-Mode steering/finding/binding.
     *
     * @param   state - an
     *
     * @return  none
     */
    static void zclLight_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData )
    {
    #ifdef LCD_SUPPORTED
      char *pStr;
      uint8 err;
    #endif
    
      // time to go into identify mode
      if ( state == EZMODE_STATE_IDENTIFYING )
      {
    #ifdef LCD_SUPPORTED
        HalLcdWriteString( "EZMode", HAL_LCD_LINE_2 );
    #endif
    
        zclLight_IdentifyTime = ( EZMODE_TIME / 1000 );  // convert to seconds
        zclLight_ProcessIdentifyTimeChange();
      }
    
      // autoclosing, show what happened (success, cancelled, etc...)
      if( state == EZMODE_STATE_AUTOCLOSE )
      {
    #ifdef LCD_SUPPORTED
        pStr = NULL;
        err = pData->sAutoClose.err;
        if ( err == EZMODE_ERR_SUCCESS )
        {
          pStr = "EZMode: Success";
        }
        else if ( err == EZMODE_ERR_NOMATCH )
        {
          pStr = "EZMode: NoMatch"; // not a match made in heaven
        }
        if ( pStr )
        {
          if ( giLightScreenMode == LIGHT_MAINMODE )
          {
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
          }
        }
    #endif
      }
    
      // finished, either show DstAddr/EP, or nothing (depending on success or not)
      if( state == EZMODE_STATE_FINISH )
      {
        // turn off identify mode
        zclLight_IdentifyTime = 0;
        zclLight_ProcessIdentifyTimeChange();
    
    #ifdef LCD_SUPPORTED
        // if successful, inform user which nwkaddr/ep we bound to
        pStr = NULL;
        err = pData->sFinish.err;
        if( err == EZMODE_ERR_SUCCESS )
        {
          // already stated on autoclose
        }
        else if ( err == EZMODE_ERR_CANCELLED )
        {
          pStr = "EZMode: Cancel";
        }
        else if ( err == EZMODE_ERR_BAD_PARAMETER )
        {
          pStr = "EZMode: BadParm";
        }
        else if ( err == EZMODE_ERR_TIMEDOUT )
        {
          pStr = "EZMode: TimeOut";
        }
        if ( pStr )
        {
          if ( giLightScreenMode == LIGHT_MAINMODE )
          {
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
          }
        }
    #endif
        // show main UI screen 3 seconds after binding
        osal_start_timerEx( zclLight_TaskID, LIGHT_MAIN_SCREEN_EVT, 3000 );
      }
    }
    #endif // ZCL_EZMODE
    
    /****************************************************************************
    ****************************************************************************/
    
    
    

    /**************************************************************************************************
      Filename:       zcl_samplesw.c
      Revised:        $Date: 2014-10-24 16:04:46 -0700 (Fri, 24 Oct 2014) $
      Revision:       $Revision: 40796 $
    
      Description:    Zigbee Cluster Library - sample device application.
    
    
      Copyright 2006-2013 Texas Instruments Incorporated. All rights reserved.
    
      IMPORTANT: Your use of this Software is limited to those specific rights
      granted under the terms of a software license agreement between the user
      who downloaded the software, his/her employer (which must be your employer)
      and Texas Instruments Incorporated (the "License").  You may not use this
      Software unless you agree to abide by the terms of the License. The License
      limits your use, and you acknowledge, that the Software may not be modified,
      copied or distributed unless embedded on a Texas Instruments microcontroller
      or used solely and exclusively in conjunction with a Texas Instruments radio
      frequency transceiver, which is integrated into your product.  Other than for
      the foregoing purpose, you may not use, reproduce, copy, prepare derivative
      works of, modify, distribute, perform, display or sell this Software and/or
      its documentation for any purpose.
    
      YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
      PROVIDED �AS IS� WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
      INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
      NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
      TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
      NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
      LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
      INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
      OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
      OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
      (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
    
      Should you have any questions regarding your right to use this Software,
      contact Texas Instruments Incorporated at www.TI.com.
    **************************************************************************************************/
    
    /*********************************************************************
      This device will be like an On/Off Switch device. This application
      is not intended to be a On/Off Switch device, but will use the device
      description to implement this sample code.
    
      ----------------------------------------
      Main:
        - SW1: Toggle remote light
        - SW2: Invoke EZMode
        - SW4: Enable/Disable Permit Join
        - SW5: Go to Help screen
      ----------------------------------------
    *********************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    #include "ZComDef.h"
    #include "OSAL.h"
    #include "AF.h"
    #include "ZDApp.h"
    #include "ZDObject.h"
    #include "ZDProfile.h"
    #include "MT_SYS.h"
    
    #include "zcl.h"
    #include "zcl_general.h"
    #include "zcl_ha.h"
    #include "zcl_sw.h"
    #include "zcl_ezmode.h"
    
    #include "onboard.h"
    
    /* HAL */
    #include "hal_lcd.h"
    #include "hal_led.h"
    #include "hal_key.h"
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    #include "zcl_ota.h"
    #include "hal_ota.h"
    #endif
    
    
    /*********************************************************************
     * MACROS
     */
    
    /*********************************************************************
     * CONSTANTS
     */
    /*********************************************************************
     * TYPEDEFS
     */
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    byte zclSw_TaskID;
    
    uint8 zclSwSeqNum;
    
    uint8 zclSw_OnOffSwitchType = ON_OFF_SWITCH_TYPE_TOGGLE;
    
    uint8 zclSw_OnOffSwitchActions = ON_OFF_SWITCH_ACTIONS_2;   // Toggle -> Toggle
    
    /*********************************************************************
     * GLOBAL FUNCTIONS
     */
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    #ifdef ZCL_ON_OFF
    afAddrType_t zclSw_DstAddr;
    #endif
    
    #ifdef ZCL_EZMODE
    static void zclSw_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg );
    static void zclSw_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData );
    
    static const zclEZMode_RegisterData_t zclSw_RegisterEZModeData =
    {
      &zclSw_TaskID,
      SW_EZMODE_NEXTSTATE_EVT,
      SW_EZMODE_TIMEOUT_EVT,
      &zclSwSeqNum,
      zclSw_EZModeCB
    };
    
    // NOT ZLC_EZMODE, Use EndDeviceBind
    #else
    
    static cId_t bindingOutClusters[] =
    {
      ZCL_CLUSTER_ID_GEN_ON_OFF
    };
    #define ZCLSW_BINDINGLIST   (sizeof(bindingOutClusters)/sizeof(bindingOutClusters[0]))
    #endif  // ZLC_EZMODE
    
    // Endpoint to allow SYS_APP_MSGs
    static endPointDesc_t sampleSw_TestEp =
    {
      SW_ENDPOINT,                  // endpoint
      &zclSw_TaskID,
      (SimpleDescriptionFormat_t *)NULL,  // No Simple description for this test endpoint
      (afNetworkLatencyReq_t)0            // No Network Latency req
    };
    
    uint8 giSwScreenMode = SW_MAINMODE;   // display the main screen mode first
    
    static uint8 aProcessCmd[] = { 1, 0, 0, 0 }; // used for reset command, { length + cmd0 + cmd1 + data }
    
    uint8 gPermitDuration = 0;    // permit joining default to disabled
    
    devStates_t zclSw_NwkState = DEV_INIT;
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    #define DEVICE_POLL_RATE                 8000   // Poll rate for end device
    #endif
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    static void zclSw_HandleKeys( byte shift, byte keys );
    static void zclSw_BasicResetCB( void );
    static void zclSw_IdentifyCB( zclIdentify_t *pCmd );
    static void zclSw_IdentifyQueryRspCB(  zclIdentifyQueryRsp_t *pRsp );
    static void zclSw_ProcessIdentifyTimeChange( void );
    
    // app display functions
    void zclSw_LcdDisplayUpdate(void);
    void zclSw_LcdDisplayMainMode(void);
    void zclSw_LcdDisplayHelpMode(void);
    
    // Functions to process ZCL Foundation incoming Command/Response messages
    static void zclSw_ProcessIncomingMsg( zclIncomingMsg_t *msg );
    #ifdef ZCL_READ
    static uint8 zclSw_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    #ifdef ZCL_WRITE
    static uint8 zclSw_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    static uint8 zclSw_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg );
    #ifdef ZCL_DISCOVER
    static uint8 zclSw_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclSw_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg );
    static uint8 zclSw_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg );
    #endif
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    static void zclSw_ProcessOTAMsgs( zclOTA_CallbackMsg_t* pMsg );
    #endif
    
    /*********************************************************************
     * ZCL General Profile Callback table
     */
    static zclGeneral_AppCallbacks_t zclSw_CmdCallbacks =
    {
      zclSw_BasicResetCB,               // Basic Cluster Reset command
      zclSw_IdentifyCB,                 // Identify command
    #ifdef ZCL_EZMODE
      NULL,                                   // Identify EZ-Mode Invoke command
      NULL,                                   // Identify Update Commission State command
    #endif
      NULL,                                   // Identify Trigger Effect command
      zclSw_IdentifyQueryRspCB,         // Identify Query Response command
      NULL,                                   // On/Off cluster commands
      NULL,                                   // On/Off cluster enhanced command Off with Effect
      NULL,                                   // On/Off cluster enhanced command On with Recall Global Scene
      NULL,                                   // On/Off cluster enhanced command On with Timed Off
    #ifdef ZCL_LEVEL_CTRL
      NULL,                                   // Level Control Move to Level command
      NULL,                                   // Level Control Move command
      NULL,                                   // Level Control Step command
      NULL,                                   // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPS
      NULL,                                   // Group Response commands
    #endif
    #ifdef ZCL_SCENES
      NULL,                                   // Scene Store Request command
      NULL,                                   // Scene Recall Request command
      NULL,                                   // Scene Response command
    #endif
    #ifdef ZCL_ALARMS
      NULL,                                   // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXT
      NULL,                                   // Get Event Log command
      NULL,                                   // Publish Event Log command
    #endif
      NULL,                                   // RSSI Location command
      NULL                                    // RSSI Location Response command
    };
    
    
    /*********************************************************************
     * STATUS STRINGS
     */
    #ifdef LCD_SUPPORTED
    const char sDeviceName[]   = "  Sample Switch";
    const char sClearLine[]    = " ";
    const char sSwLight[]      = "SW1: ToggleLight";
    const char sSwEZMode[]     = "SW2: EZ-Mode";
    const char sSwHelp[]       = "SW5: Help";
    const char sCmdSent[]      = "  COMMAND SENT";
    #endif
    
    /*********************************************************************
     * @fn          zclSw_Init
     *
     * @brief       Initialization function for the zclGeneral layer.
     *
     * @param       none
     *
     * @return      none
     */
    void zclSw_Init( byte task_id )
    {
      zclSw_TaskID = task_id;
    
    #ifdef ZCL_ON_OFF
      // Set destination address to indirect
      zclSw_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
      zclSw_DstAddr.endPoint = 8;
      zclSw_DstAddr.addr.shortAddr = 0;
    #endif
    
      // This app is part of the Home Automation Profile
      zclHA_Init( &zclSw_SimpleDesc );
    
      // Register the ZCL General Cluster Library callback functions
      zclGeneral_RegisterCmdCallbacks( SW_ENDPOINT, &zclSw_CmdCallbacks );
    
      // Register the application's attribute list
      zcl_registerAttrList( SW_ENDPOINT, SW_MAX_ATTRIBUTES, zclSw_Attrs );
    
      // Register the Application to receive the unprocessed Foundation command/response messages
      zcl_registerForMsg( zclSw_TaskID );
    
    #ifdef ZCL_EZMODE
      // Register EZ-Mode
      zcl_RegisterEZMode( &zclSw_RegisterEZModeData );
    
      // Register with the ZDO to receive Match Descriptor Responses
      ZDO_RegisterForZDOMsg(task_id, Match_Desc_rsp);
    #endif
    
      // Register for all key events - This app will handle all key events
      RegisterForKeys( zclSw_TaskID );
    
      // Register for a test endpoint
      afRegister( &sampleSw_TestEp );
    
      ZDO_RegisterForZDOMsg( zclSw_TaskID, End_Device_Bind_rsp );
      ZDO_RegisterForZDOMsg( zclSw_TaskID, Match_Desc_rsp );
    
    #ifdef LCD_SUPPORTED
      HalLcdWriteString ( (char *)sDeviceName, HAL_LCD_LINE_3 );
    #endif
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
      // Register for callback events from the ZCL OTA
      zclOTA_Register(zclSw_TaskID);
    #endif
    
    }
    
    /*********************************************************************
     * @fn          zclSample_event_loop
     *
     * @brief       Event Loop Processor for zclGeneral.
     *
     * @param       none
     *
     * @return      none
     */
    uint16 zclSw_event_loop( uint8 task_id, uint16 events )
    {
      afIncomingMSGPacket_t *MSGpkt;
      (void)task_id;  // Intentionally unreferenced parameter
    
      if ( events & SYS_EVENT_MSG )
      {
        while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( zclSw_TaskID )) )
        {
          switch ( MSGpkt->hdr.event )
          {
    #ifdef ZCL_EZMODE
            case ZDO_CB_MSG:
              zclSw_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
              break;
    #endif
            case ZCL_INCOMING_MSG:
              // Incoming ZCL Foundation command/response messages
              zclSw_ProcessIncomingMsg( (zclIncomingMsg_t *)MSGpkt );
              break;
    
            case KEY_CHANGE:
              zclSw_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
              break;
    
            case ZDO_STATE_CHANGE:
              zclSw_NwkState = (devStates_t)(MSGpkt->hdr.status);
    
              // now on the network
              if ( (zclSw_NwkState == DEV_ZB_COORD) ||
                   (zclSw_NwkState == DEV_ROUTER)   ||
                   (zclSw_NwkState == DEV_END_DEVICE) )
              {
    #ifndef HOLD_AUTO_START
                giSwScreenMode = SW_MAINMODE;
                zclSw_LcdDisplayUpdate();
    #endif
    #ifdef ZCL_EZMODE
                zcl_EZModeAction( EZMODE_ACTION_NETWORK_STARTED, NULL );
    #endif
              }
              break;
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
            case ZCL_OTA_CALLBACK_IND:
              zclSw_ProcessOTAMsgs( (zclOTA_CallbackMsg_t*)MSGpkt  );
              break;
    #endif
    
            default:
              break;
          }
    
          // Release the memory
          osal_msg_deallocate( (uint8 *)MSGpkt );
        }
    
        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
      }
    
      if ( events & SW_IDENTIFY_TIMEOUT_EVT )
      {
        zclSw_IdentifyTime = 10;
        zclSw_ProcessIdentifyTimeChange();
    
        return ( events ^ SW_IDENTIFY_TIMEOUT_EVT );
      }
    
      if ( events & SW_MAIN_SCREEN_EVT )
      {
        giSwScreenMode = SW_MAINMODE;
    
        zclSw_LcdDisplayUpdate();
    
    #ifdef LCD_SUPPORTED
        HalLcdWriteString( (char *)sClearLine, HAL_LCD_LINE_2 );
    #endif
        return ( events ^ SW_MAIN_SCREEN_EVT );
      }
    
    #ifdef ZCL_EZMODE
      if ( events & SW_EZMODE_NEXTSTATE_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_PROCESS, NULL );   // going on to next state
        return ( events ^ SW_EZMODE_NEXTSTATE_EVT );
      }
    
      if ( events & SW_EZMODE_TIMEOUT_EVT )
      {
        zcl_EZModeAction ( EZMODE_ACTION_TIMED_OUT, NULL ); // EZ-Mode timed out
        return ( events ^ SW_EZMODE_TIMEOUT_EVT );
      }
    #endif // ZLC_EZMODE
    
      // Discard unknown events
      return 0;
    }
    
    /*********************************************************************
     * @fn      zclSw_HandleKeys
     *
     * @brief   Handles all key events for this device.
     *
     * @param   shift - true if in shift/alt.
     * @param   keys - bit field for key events. Valid entries:
     *                 HAL_KEY_SW_5
     *                 HAL_KEY_SW_4
     *                 HAL_KEY_SW_2
     *                 HAL_KEY_SW_1
     *
     * @return  none
     */
    static void zclSw_HandleKeys( byte shift, byte keys )
    {
      // toggle remote light
      if ( keys & HAL_KEY_SW_1 )
      {
        giSwScreenMode = SW_MAINMODE;   // remove help screen if there
    
        // Using this as the "Light Switch"
    #ifdef ZCL_ON_OFF
        zclGeneral_SendOnOff_CmdToggle( SW_ENDPOINT, &zclSw_DstAddr, FALSE, 0 );
    #endif
        
        
      zclReadCmd_t *pReadCmd;
    
      pReadCmd = osal_mem_alloc( sizeof(zclReadCmd_t) + sizeof(uint16) );
      if ( pReadCmd != NULL )
      {
        pReadCmd->numAttr = 1;
        pReadCmd->attrID[0] = ATTRID_ON_OFF;
     
        zcl_SendRead( SW_ENDPOINT,&zclSw_DstAddr,
                            ZCL_CLUSTER_ID_GEN_ON_OFF,pReadCmd,
                            ZCL_FRAME_CLIENT_SERVER_DIR, TRUE,zclSwSeqNum);
      }
    
      osal_mem_free( pReadCmd );    
        
        
    #ifdef LCD_SUPPORTED
        HalLcdWriteString( (char *)sCmdSent, HAL_LCD_LINE_2 );
    
        // clear message on screen after 3 seconds
        osal_start_timerEx( zclSw_TaskID, SW_MAIN_SCREEN_EVT, 3000 );
    #endif
      }
    
      // invoke EZ-Mode
      if ( keys & HAL_KEY_SW_2 )
      {
        giSwScreenMode = SW_MAINMODE;   // remove help screen if there
    
    #ifdef ZCL_EZMODE
        {
          zclEZMode_InvokeData_t ezModeData;
          static uint16 clusterIDs[] = { ZCL_CLUSTER_ID_GEN_ON_OFF };   // only bind on the on/off cluster
    
          // Invoke EZ-Mode
          ezModeData.endpoint = SW_ENDPOINT; // endpoint on which to invoke EZ-Mode
          if ( (zclSw_NwkState == DEV_ZB_COORD) ||
                   (zclSw_NwkState == DEV_ROUTER)   ||
                   (zclSw_NwkState == DEV_END_DEVICE) )
          {
            ezModeData.onNetwork = TRUE;      // node is already on the network
          }
          else
          {
            ezModeData.onNetwork = FALSE;     // node is not yet on the network
          }
          ezModeData.initiator = TRUE;        // OnOffSwitch is an initiator
          ezModeData.numActiveOutClusters = 1;   // active output cluster
          ezModeData.pActiveOutClusterIDs = clusterIDs;
          ezModeData.numActiveInClusters = 0;  // no active input clusters
          ezModeData.pActiveInClusterIDs = NULL;
          zcl_InvokeEZMode( &ezModeData );
    
     #ifdef LCD_SUPPORTED
          HalLcdWriteString( "EZMode", HAL_LCD_LINE_2 );
     #endif
        }
    
    #else // NOT ZCL_EZMODE
        // bind to remote light
        zAddrType_t dstAddr;
        HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
    
        // Initiate an End Device Bind Request, this bind request will
        // only use a cluster list that is important to binding.
        dstAddr.addrMode = afAddr16Bit;
        dstAddr.addr.shortAddr = 0;   // Coordinator makes the match
        ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
                               SW_ENDPOINT,
                               ZCL_HA_PROFILE_ID,
                               0, NULL,   // No incoming clusters to bind
                               ZCLSW_BINDINGLIST, bindingOutClusters,
                               TRUE );
    #endif // ZCL_EZMODE
      }
    
      // toggle permit join
      if ( keys & HAL_KEY_SW_4 )
      {
        giSwScreenMode = SW_MAINMODE;   // remove help screen if there
    
        if ( ( zclSw_NwkState == DEV_ZB_COORD ) ||
             ( zclSw_NwkState == DEV_ROUTER ) )
        {
          zAddrType_t tmpAddr;
    
          tmpAddr.addrMode = Addr16Bit;
          tmpAddr.addr.shortAddr = NLME_GetShortAddr();
    
          // toggle permit join
          gPermitDuration = gPermitDuration ? 0 : 0xff;
    
          // Trust Center significance is always true
          ZDP_MgmtPermitJoinReq( &tmpAddr, gPermitDuration, TRUE, FALSE );
        }
      }
    
      if ( shift && ( keys & HAL_KEY_SW_5 ) )
      {
        zclSw_BasicResetCB();
      }
      else if ( keys & HAL_KEY_SW_5 )
      {
        giSwScreenMode = giSwScreenMode ? SW_MAINMODE : SW_HELPMODE;
    #ifdef LCD_SUPPORTED
        HalLcdWriteString( (char *)sClearLine, HAL_LCD_LINE_2 );
    #endif
      }
    
      // update the display
      zclSw_LcdDisplayUpdate();
    }
    
    /*********************************************************************
     * @fn      zclSw_LcdDisplayUpdate
     *
     * @brief   Called to update the LCD display.
     *
     * @param   none
     *
     * @return  none
     */
    void zclSw_LcdDisplayUpdate(void)
    {
      if ( giSwScreenMode == SW_HELPMODE )
      {
        zclSw_LcdDisplayHelpMode();
      }
      else
      {
        zclSw_LcdDisplayMainMode();
      }
    }
    
    /*********************************************************************
     * @fn      zclSw_LcdDisplayMainMode
     *
     * @brief   Called to display the main screen on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    void zclSw_LcdDisplayMainMode(void)
    {
      if ( zclSw_NwkState == DEV_ZB_COORD )
      {
        zclHA_LcdStatusLine1(0);
      }
      else if ( zclSw_NwkState == DEV_ROUTER )
      {
        zclHA_LcdStatusLine1(1);
      }
      else if ( zclSw_NwkState == DEV_END_DEVICE )
      {
        zclHA_LcdStatusLine1(2);
      }
    
    #ifdef LCD_SUPPORTED
      if ( ( zclSw_NwkState == DEV_ZB_COORD ) ||
           ( zclSw_NwkState == DEV_ROUTER ) )
      {
        // display help key with permit join status
        if ( gPermitDuration )
        {
          HalLcdWriteString("SW5: Help      *", HAL_LCD_LINE_3);
        }
        else
        {
          HalLcdWriteString("SW5: Help       ", HAL_LCD_LINE_3);
        }
      }
      else
      {
        // display help key
        HalLcdWriteString((char *)sSwHelp, HAL_LCD_LINE_3);
      }
    #endif
    }
    
    /*********************************************************************
     * @fn      zclSw_LcdDisplayHelpMode
     *
     * @brief   Called to display the SW options on the LCD.
     *
     * @param   none
     *
     * @return  none
     */
    void zclSw_LcdDisplayHelpMode(void)
    {
    #ifdef LCD_SUPPORTED
      HalLcdWriteString( (char *)sSwLight, HAL_LCD_LINE_1 );
      HalLcdWriteString( (char *)sSwEZMode, HAL_LCD_LINE_2 );
      HalLcdWriteString( (char *)sSwHelp, HAL_LCD_LINE_3 );
    #endif
    }
    
    /*********************************************************************
     * @fn      zclSw_ProcessIdentifyTimeChange
     *
     * @brief   Called to process any change to the IdentifyTime attribute.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclSw_ProcessIdentifyTimeChange( void )
    {
      if ( zclSw_IdentifyTime > 0 )
      {
        osal_start_timerEx( zclSw_TaskID, SW_IDENTIFY_TIMEOUT_EVT, 1000 );
        HalLedBlink ( HAL_LED_4, 0xFF, HAL_LED_DEFAULT_DUTY_CYCLE, HAL_LED_DEFAULT_FLASH_TIME );
      }
      else
      {
        if ( zclSw_OnOff )
          HalLedSet ( HAL_LED_4, HAL_LED_MODE_ON );
        else
          HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
        osal_stop_timerEx( zclSw_TaskID, SW_IDENTIFY_TIMEOUT_EVT );
      }
    }
    
    /*********************************************************************
     * @fn      zclSw_BasicResetCB
     *
     * @brief   Callback from the ZCL General Cluster Library
     *          to set all the Basic Cluster attributes to  default values.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclSw_BasicResetCB( void )
    {
      // Put device back to factory default settings
      zgWriteStartupOptions( ZG_STARTUP_SET, 3 );   // bit set both default configuration and default network
    
      // restart device
      MT_SysCommandProcessing( aProcessCmd );
    }
    
    /*********************************************************************
     * @fn      zclSw_IdentifyCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Command for this application.
     *
     * @param   srcAddr - source address and endpoint of the response message
     * @param   identifyTime - the number of seconds to identify yourself
     *
     * @return  none
     */
    static void zclSw_IdentifyCB( zclIdentify_t *pCmd )
    {
      zclSw_IdentifyTime = pCmd->identifyTime;
      zclSw_ProcessIdentifyTimeChange();
    }
    
    /*********************************************************************
     * @fn      zclSw_IdentifyQueryRspCB
     *
     * @brief   Callback from the ZCL General Cluster Library when
     *          it received an Identity Query Response Command for this application.
     *
     * @param   srcAddr - source address
     * @param   timeout - number of seconds to identify yourself (valid for query response)
     *
     * @return  none
     */
    static void zclSw_IdentifyQueryRspCB(  zclIdentifyQueryRsp_t *pRsp )
    {
      (void)pRsp;
    #ifdef ZCL_EZMODE
      {
        zclEZMode_ActionData_t data;
        data.pIdentifyQueryRsp = pRsp;
        zcl_EZModeAction ( EZMODE_ACTION_IDENTIFY_QUERY_RSP, &data );
      }
    #endif
    }
    
    /******************************************************************************
     *
     *  Functions for processing ZCL Foundation incoming Command/Response messages
     *
     *****************************************************************************/
    
    /*********************************************************************
     * @fn      zclSw_ProcessIncomingMsg
     *
     * @brief   Process ZCL Foundation incoming message
     *
     * @param   pInMsg - pointer to the received message
     *
     * @return  none
     */
    static void zclSw_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg )
    {
      switch ( pInMsg->zclHdr.commandID )
      {
    #ifdef ZCL_READ
        case ZCL_CMD_READ_RSP:
          zclSw_ProcessInReadRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_WRITE
        case ZCL_CMD_WRITE_RSP:
          zclSw_ProcessInWriteRspCmd( pInMsg );
          break;
    #endif
    #ifdef ZCL_REPORT
        // See ZCL Test Applicaiton (zcl_testapp.c) for sample code on Attribute Reporting
        case ZCL_CMD_CONFIG_REPORT:
          //zclSw_ProcessInConfigReportCmd( pInMsg );
          break;
    
        case ZCL_CMD_CONFIG_REPORT_RSP:
          //zclSw_ProcessInConfigReportRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG:
          //zclSw_ProcessInReadReportCfgCmd( pInMsg );
          break;
    
        case ZCL_CMD_READ_REPORT_CFG_RSP:
          //zclSw_ProcessInReadReportCfgRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_REPORT:
          //zclSw_ProcessInReportCmd( pInMsg );
          break;
    #endif
        case ZCL_CMD_DEFAULT_RSP:
          zclSw_ProcessInDefaultRspCmd( pInMsg );
          break;
    #ifdef ZCL_DISCOVER
        case ZCL_CMD_DISCOVER_CMDS_RECEIVED_RSP:
          zclSw_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_CMDS_GEN_RSP:
          zclSw_ProcessInDiscCmdsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_RSP:
          zclSw_ProcessInDiscAttrsRspCmd( pInMsg );
          break;
    
        case ZCL_CMD_DISCOVER_ATTRS_EXT_RSP:
          zclSw_ProcessInDiscAttrsExtRspCmd( pInMsg );
          break;
    #endif
        default:
          break;
      }
    
      if ( pInMsg->attrCmd )
        osal_mem_free( pInMsg->attrCmd );
    }
    
    #ifdef ZCL_READ
    /*********************************************************************
     * @fn      zclSw_ProcessInReadRspCmd
     *
     * @brief   Process the "Profile" Read Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclReadRspCmd_t *readRspCmd;
      uint8 i;
    
      readRspCmd = (zclReadRspCmd_t *)pInMsg->attrCmd;
      for (i = 0; i < readRspCmd->numAttr; i++)
      {
        // Notify the originator of the results of the original read attributes
        // attempt and, for each successfull request, the value of the requested
        // attribute
      }
    
      return TRUE;
    }
    #endif // ZCL_READ
    
    #ifdef ZCL_WRITE
    /*********************************************************************
     * @fn      zclSw_ProcessInWriteRspCmd
     *
     * @brief   Process the "Profile" Write Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclWriteRspCmd_t *writeRspCmd;
      uint8 i;
    
      writeRspCmd = (zclWriteRspCmd_t *)pInMsg->attrCmd;
      for (i = 0; i < writeRspCmd->numAttr; i++)
      {
        // Notify the device of the results of the its original write attributes
        // command.
      }
    
      return TRUE;
    }
    #endif // ZCL_WRITE
    
    /*********************************************************************
     * @fn      zclSw_ProcessInDefaultRspCmd
     *
     * @brief   Process the "Profile" Default Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg )
    {
      // zclDefaultRspCmd_t *defaultRspCmd = (zclDefaultRspCmd_t *)pInMsg->attrCmd;
      // Device is notified of the Default Response command.
      (void)pInMsg;
      return TRUE;
    }
    
    #ifdef ZCL_DISCOVER
    /*********************************************************************
     * @fn      zclSw_ProcessInDiscCmdsRspCmd
     *
     * @brief   Process the Discover Commands Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDiscCmdsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverCmdsCmdRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverCmdsCmdRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numCmd; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return TRUE;
    }
    
    /*********************************************************************
     * @fn      zclSw_ProcessInDiscAttrsRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDiscAttrsRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsRspCmd_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsRspCmd_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return TRUE;
    }
    
    /*********************************************************************
     * @fn      zclSw_ProcessInDiscAttrsExtRspCmd
     *
     * @brief   Process the "Profile" Discover Attributes Extended Response Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static uint8 zclSw_ProcessInDiscAttrsExtRspCmd( zclIncomingMsg_t *pInMsg )
    {
      zclDiscoverAttrsExtRsp_t *discoverRspCmd;
      uint8 i;
    
      discoverRspCmd = (zclDiscoverAttrsExtRsp_t *)pInMsg->attrCmd;
      for ( i = 0; i < discoverRspCmd->numAttr; i++ )
      {
        // Device is notified of the result of its attribute discovery command.
      }
    
      return TRUE;
    }
    #endif // ZCL_DISCOVER
    
    #if ZCL_EZMODE
    /*********************************************************************
     * @fn      zclSw_ProcessZDOMsgs
     *
     * @brief   Called when this node receives a ZDO/ZDP response.
     *
     * @param   none
     *
     * @return  status
     */
    static void zclSw_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg )
    {
    
      // Let EZ-Mode know of the Match Descriptor Reponse (same as ActiveEP Response)
      if ( pMsg->clusterID == Match_Desc_rsp )
      {
        zclEZMode_ActionData_t data;
        ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( pMsg );
        data.pMatchDescRsp = pRsp;
        zcl_EZModeAction( EZMODE_ACTION_MATCH_DESC_RSP, &data );
        osal_mem_free(pRsp);
      }
    }
    
    /*********************************************************************
     * @fn      zclSw_EZModeCB
     *
     * @brief   The Application is informed of events. This can be used to show on the UI what is
    *           going on during EZ-Mode steering/finding/binding.
     *
     * @param   state - an
     *
     * @return  none
     */
    static void zclSw_EZModeCB( zlcEZMode_State_t state, zclEZMode_CBData_t *pData )
    {
    #ifdef LCD_SUPPORTED
      char szLine[20];
      char *pStr;
      uint8 err;
    #endif
    
      // time to go into identify mode
      if ( state == EZMODE_STATE_IDENTIFYING )
      {
        zclSw_IdentifyTime = (EZMODE_TIME / 1000);  // convert to seconds
        zclSw_ProcessIdentifyTimeChange();
      }
    
      // autoclosing, show what happened (success, cancelled, etc...)
      if( state == EZMODE_STATE_AUTOCLOSE )
      {
    #ifdef LCD_SUPPORTED
        pStr = NULL;
        err = pData->sAutoClose.err;
        if ( err == EZMODE_ERR_SUCCESS )
        {
          pStr = "EZMode: Success";
        }
        else if ( err == EZMODE_ERR_NOMATCH )
        {
          pStr = "EZMode: NoMatch"; // not a match made in heaven
        }
        if ( pStr )
        {
          if ( giSwScreenMode == SW_MAINMODE )
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
        }
    #endif
      }
    
      // finished, either show DstAddr/EP, or nothing (depending on success or not)
      if( state == EZMODE_STATE_FINISH )
      {
        // turn off identify mode
        zclSw_IdentifyTime = 0;
        zclSw_ProcessIdentifyTimeChange();
    
    #ifdef LCD_SUPPORTED
        // if successful, inform user which nwkaddr/ep we bound to
        pStr = NULL;
        err = pData->sFinish.err;
        if( err == EZMODE_ERR_SUCCESS )
        {
          // "EZDst:1234 EP:34"
          osal_memcpy(szLine, "EZDst:", 6);
          zclHA_uint16toa( pData->sFinish.nwkaddr, &szLine[6]);
          osal_memcpy(&szLine[10], " EP:", 4);
          _ltoa( pData->sFinish.ep, (void *)(&szLine[14]), 16 );  // _ltoa NULL terminates
          pStr = szLine;
        }
        else if ( err == EZMODE_ERR_BAD_PARAMETER )
        {
          pStr = "EZMode: BadParm";
        }
        else if ( err == EZMODE_ERR_CANCELLED )
        {
          pStr = "EZMode: Cancel";
        }
        else
        {
          pStr = "EZMode: TimeOut";
        }
        if ( pStr )
        {
          if ( giSwScreenMode == SW_MAINMODE )
            HalLcdWriteString ( pStr, HAL_LCD_LINE_2 );
        }
    #endif  // LCD_SUPPORTED
        // show main UI screen 3 seconds after binding
        osal_start_timerEx( zclSw_TaskID, SW_MAIN_SCREEN_EVT, 3000 );
      }
    
    }
    
    #endif // ZCL_EZMODE
    
    #if defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    /*********************************************************************
     * @fn      zclSw_ProcessOTAMsgs
     *
     * @brief   Called to process callbacks from the ZCL OTA.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclSw_ProcessOTAMsgs( zclOTA_CallbackMsg_t* pMsg )
    {
      uint8 RxOnIdle;
    
      switch(pMsg->ota_event)
      {
      case ZCL_OTA_START_CALLBACK:
        if (pMsg->hdr.status == ZSuccess)
        {
          // Speed up the poll rate
          RxOnIdle = TRUE;
          ZMacSetReq( ZMacRxOnIdle, &RxOnIdle );
          NLME_SetPollRate( 2000 );
        }
        break;
    
      case ZCL_OTA_DL_COMPLETE_CALLBACK:
        if (pMsg->hdr.status == ZSuccess)
        {
          // Reset the CRC Shadow and reboot.  The bootloader will see the
          // CRC shadow has been cleared and switch to the new image
          HalOTAInvRC();
          SystemReset();
        }
        else
        {
          // slow the poll rate back down.
          RxOnIdle = FALSE;
          ZMacSetReq( ZMacRxOnIdle, &RxOnIdle );
          NLME_SetPollRate(DEVICE_POLL_RATE);
        }
        break;
    
      default:
        break;
      }
    }
    #endif // defined (OTA_CLIENT) && (OTA_CLIENT == TRUE)
    
    /****************************************************************************
    ****************************************************************************/
    
    
    

  • Do you have sniffer log for this?