/**
 * Copyright (c) 2018 - 2019, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/** @file
 *
 * @defgroup zigbee_examples_light_bulb main.c
 * @{
 * @ingroup zigbee_examples
 * @brief Dimmable light sample (HA profile)
 */

#include "sdk_config.h"
#include "zboss_api.h"
#include "zb_mem_config_med.h"
#include "zb_error_handler.h"
#include "zb_nrf52840_internal.h"
#include "zigbee_helpers.h"

#include "bsp.h"
#include "boards.h"
#include "app_timer.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf.h"

/**User Include file*********/
#include "uart_config.h"
#include "gpio_config.h"
#include "timer_config.h"
#include "commands.h" 
#include "uart_statemachine.h" 
#include "app_flash_memory.h"

#include "zb_custom1_thermostat.h"
#include "custom_app_event.h"


                                
/**< Scan only one, predefined channel to find the coordinator. */
#define IEEE_CHANNEL_MASK                (ZB_TRANSCEIVER_ALL_CHANNELS_MASK)    // (1l << ZIGBEE_CHANNEL)

#define ERASE_PERSISTENT_CONFIG           ZB_FALSE                              /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. */


#define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_2                       /**< LED indicating that light switch successfully joind ZigBee network. */


#if !defined ZB_ED_ROLE
#error Define ZB_ED_ROLE to compile End Device source code.
#endif



/******************************************************************
* GLOBAL VARIABLES
*
*******************************************************************/
uint16_t ui16CurrentTemp =0, ui16OccupiedHeatSetpoint = 0, ui16UnOccupiedHeatSetpoint = 0;
uint8_t  ui8LocalTemperatureCalibration = 0;
uint32_t ui32HostflagsData = 0;

bool boolSetTemperature = false;
bool boolGetStatus = false;
bool boolSetHostflags = false;
bool boolSendDeviceConfig = false;
/******************************************************************************************
*EXTERNAL VARIABLES
*
*******************************************************************************************/
extern bool boolReady;
extern bool boolMCUInterrupt;
extern bool boolSetCommand;
extern uint8_t ui8SendDeviceConfig[BUFFER_SIZE];

extern App_tsEventUart sAppUartEvent;
extern E_StateMachineThermostat e_StateMachineThermostat;
/******************************************************************************************
*FUNCTIONS 
*
*******************************************************************************************/
/* Declare attribute list for Basic cluster. */
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(basic_attr_list,
                                     &m_dev_ctx.basic_attr.zcl_version,
                                     &m_dev_ctx.basic_attr.app_version,
                                     &m_dev_ctx.basic_attr.stack_version,
                                     &m_dev_ctx.basic_attr.hw_version,
                                     m_dev_ctx.basic_attr.mf_name,
                                     m_dev_ctx.basic_attr.model_id,
                                     m_dev_ctx.basic_attr.date_code,
                                     &m_dev_ctx.basic_attr.power_source,
                                     m_dev_ctx.basic_attr.location_id,
                                     &m_dev_ctx.basic_attr.ph_env,
                                     m_dev_ctx.basic_attr.sw_ver);

/* Declare attribute list for Identify cluster. */
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list,
                                    &m_dev_ctx.identify_attr.identify_time);

/**power attributes**/
ZB_ZCL_DECLARE_POWER_CONFIG_BATTERY_ATTRIB_LIST_EXT(power_config_attr_list,
                                        &m_dev_ctx.power_attr.battery_voltage,
                                        &m_dev_ctx.power_attr.battery_size,
                                        &m_dev_ctx.power_attr.battery_quantity,
                                        &m_dev_ctx.power_attr.battery_rated_voltage,
                                        &m_dev_ctx.power_attr.battery_alarm_mask,
                                        &m_dev_ctx.power_attr.battery_voltage_min_threshold,
                                        &m_dev_ctx.power_attr.battery_percentage_remaining,
                                        &m_dev_ctx.power_attr.battery_voltage_threshold1,
                                        &m_dev_ctx.power_attr.battery_voltage_threshold2,
                                        &m_dev_ctx.power_attr.battery_voltage_threshold3,
                                        &m_dev_ctx.power_attr.battery_percentage_min_threshold,
                                        &m_dev_ctx.power_attr.battery_percentage_threshold1,
                                        &m_dev_ctx.power_attr.battery_percentage_threshold2,
                                        &m_dev_ctx.power_attr.battery_percentage_threshold3,
                                        &m_dev_ctx.power_attr.battery_alarm_state);

ZB_ZCL_DECLARE_TIME_ATTRIB_LIST(time_attr_list,
                                &m_dev_ctx.time_attr.timeId,
                                &m_dev_ctx.time_attr.time_status,
                                &m_dev_ctx.time_attr.time_zone,
                                &m_dev_ctx.time_attr.dst_start,
                                &m_dev_ctx.time_attr.dst_end,
                                &m_dev_ctx.time_attr.dst_shift,
                                &m_dev_ctx.time_attr.standard_time,
                                &m_dev_ctx.time_attr.local_time,
                                &m_dev_ctx.time_attr.last_settime,
                                &m_dev_ctx.time_attr.valid_untilTime);

/* Declare extended attribute list for Thermostat cluster. */
ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST_EXT(thermostat_attr_list,
                                          &m_dev_ctx.thermostat_attr.local_temperature,
                                          &m_dev_ctx.thermostat_attr.local_temperature_calibration,
                                          &m_dev_ctx.thermostat_attr.occupied_heating_setpoint,
                                          &m_dev_ctx.thermostat_attr.unoccupied_heating_setpoint,
                                          &m_dev_ctx.thermostat_attr.pi_heating_demand,
                                          &m_dev_ctx.thermostat_attr.min_heating_setpoint_limit,
                                          &m_dev_ctx.thermostat_attr.max_heating_setpoint_limit,
                                          &m_dev_ctx.thermostat_attr.remote_sensing,
                                          &m_dev_ctx.thermostat_attr.control_seq_of_operation,
                                          &m_dev_ctx.thermostat_attr.system_mode,
                                          &m_dev_ctx.thermostat_attr.trv_mode,
                                          &m_dev_ctx.thermostat_attr.set_valve_position,
                                          &m_dev_ctx.thermostat_attr.error,
                                          &m_dev_ctx.thermostat_attr.current_setpoint,
                                          &m_dev_ctx.thermostat_attr.host_flags);

/* Declare cluster list for Thermostat device (Basic, Identify, Thermostat, Fan Control, Thermostat UI). */
ZB_DECLARE_CUSTOM_THERMOSTAT_CLUSTER_LIST(thermostat_clusters,
                                      basic_attr_list,
                                      identify_attr_list,
                                      power_config_attr_list,
                                      thermostat_attr_list,
                                      time_attr_list);


ZB_HA_DECLARE_CUSTOM_THERMOSTAT_EP(thermostat_ep,
                               THERMOSTAT_SENSOR_ENDPOINT,
                               thermostat_clusters);

ZB_HA_DECLARE_CUSTOM_THERMOSTAT_CTX(thermostat_ctx, thermostat_ep);

/**@brief Function for initializing the application timer.
 */
static void timer_init(void)
{
    uint32_t error_code = app_timer_init();
    APP_ERROR_CHECK(error_code);
}

/**@brief Function for initializing the nrf log module.
 */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}


/**@brief Function for initializing LEDs.
 */
static void leds_init(void)
{
    bsp_board_init(BSP_INIT_LEDS);
}

/**@brief Function for initializing all clusters attributes.
*/
static void thermostat_clusters_attr_init(void)
{
     /* Basic cluster attributes data */
     m_dev_ctx.basic_attr.zcl_version = ZB_ZCL_VERSION;
     m_dev_ctx.basic_attr.app_version = THERMOSTAT_INIT_BASIC_APP_VERSION;
     m_dev_ctx.basic_attr.stack_version = THERMOSTAT_INIT_BASIC_STACK_VERSION;
     m_dev_ctx.basic_attr.hw_version = THERMOSTAT_INIT_BASIC_HW_VERSION;
   
    /* Use ZB_ZCL_SET_STRING_VAL to set strings, because the first byte should
     * contain string length without trailing zero.
     *
     * For example "test" string wil be encoded as:
     *   [(0x4), 't', 'e', 's', 't']
     */
      ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.mf_name,
                          THERMOSTAT_INIT_BASIC_MANUF_NAME,
                          ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_MANUF_NAME));

      ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.model_id,
                          THERMOSTAT_INIT_BASIC_MODEL_ID,
                          ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_MODEL_ID));

      ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.date_code,
                          THERMOSTAT_INIT_BASIC_DATE_CODE,
                          ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_DATE_CODE));

      m_dev_ctx.basic_attr.power_source = THERMOSTAT_INIT_BASIC_POWER_SOURCE;

      ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.location_id,
                          THERMOSTAT_INIT_BASIC_LOCATION_DESC,
                          ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_LOCATION_DESC));


      m_dev_ctx.basic_attr.ph_env = THERMOSTAT_INIT_BASIC_PH_ENV;
      //m_dev_ctx.basic_attr.sw_ver = "00000000";
      memcpy( m_dev_ctx.basic_attr.sw_ver,"00000000", 8);
    
    /* Identify cluster attributes data */
    m_dev_ctx.identify_attr.identify_time        = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;

//    /**power configuration attributes data**/
    m_dev_ctx.power_attr.battery_percentage_remaining = 0x02;
    m_dev_ctx.power_attr.battery_quantity = ZB_POWER_CONFIG_BATTERY_QUANTITY;
    m_dev_ctx.power_attr.battery_size = ZB_ZCL_POWER_CONFIG_BATTERY_SIZE_AA;

   /* Thermostat cluster attributes data */
    m_dev_ctx.thermostat_attr.local_temperature             = 0x07D0;
    m_dev_ctx.thermostat_attr.local_temperature_calibration = 0x00;
    m_dev_ctx.thermostat_attr.pi_heating_demand             = 0xFF;
    m_dev_ctx.thermostat_attr.occupied_heating_setpoint     = 0x07D0;
    m_dev_ctx.thermostat_attr.unoccupied_heating_setpoint   = 0x07D0;
    m_dev_ctx.thermostat_attr.min_heating_setpoint_limit    = 0x01F4;
    m_dev_ctx.thermostat_attr.max_heating_setpoint_limit    = 0x0BB8;
    m_dev_ctx.thermostat_attr.control_seq_of_operation      = ZB_ZCL_THERMOSTAT_CONTROL_SEQ_OF_OPERATION_HEATING_ONLY;
    m_dev_ctx.thermostat_attr.system_mode                   = ZB_ZCL_THERMOSTAT_SYSTEM_MODE_HEAT;
    m_dev_ctx.thermostat_attr.current_setpoint             = 0x0898;
    m_dev_ctx.thermostat_attr.trv_mode                     = ZB_ZCL_THERMOSTAT_TRV_MODE_DEFAULT_VALUE;
    m_dev_ctx.thermostat_attr.set_valve_position           = 0;
    m_dev_ctx.thermostat_attr.error                        = 0;

         /***time cluster attributes data**/
    m_dev_ctx.time_attr.timeId = ZB_ZCL_TIME_TIME_DEFAULT_VALUE;
    m_dev_ctx.time_attr.time_status = ZB_ZCL_TIME_TIME_STATUS_DEFAULT_VALUE;

    /*local temperature set attribute**/
   ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                        ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID,
                        (zb_uint8_t *)&m_dev_ctx.thermostat_attr.local_temperature,
                        ZB_FALSE);
 
    ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                        ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID,
                        (zb_uint8_t *)&m_dev_ctx.thermostat_attr.occupied_heating_setpoint,
                        ZB_FALSE);

    ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                        ZB_ZCL_ATTR_THERMOSTAT_UNOCCUPIED_HEATING_SETPOINT_ID,
                        (zb_uint8_t *)&m_dev_ctx.thermostat_attr.unoccupied_heating_setpoint,
                        ZB_FALSE);

    ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT, 
                         ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                         ZB_ZCL_CLUSTER_SERVER_ROLE, 
                         ZB_ZCL_ATTR_THERMOSTAT_HOST_FLAG_ID, 
                         (zb_uint8_t *)&m_dev_ctx.thermostat_attr.host_flags, 
                         ZB_FALSE);

    ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT, 
                         ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                         ZB_ZCL_CLUSTER_SERVER_ROLE, 
                         ZB_ZCL_ATTR_THERMOSTAT_TRV_MODE_ID, 
                         (zb_uint8_t *)& m_dev_ctx.thermostat_attr.trv_mode, 
                         ZB_FALSE);

   /**Battery percentage value**/
   ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                        ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                        ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_REMAINING_ID,
                        (zb_uint8_t *)&m_dev_ctx.power_attr.battery_percentage_remaining,
                        ZB_FALSE);  
                                  
   ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                        ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                        ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_QUANTITY_ID,
                        (zb_uint8_t *)&m_dev_ctx.power_attr.battery_quantity,
                        ZB_FALSE);
}

/**@brief Function for local temperature
 *
 * @param[in]   new_value local temp value
 */
void localTemperatureValue(zb_uint16_t ui16local_tempvalue)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                     ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                                     ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                     ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID, 
                                     (zb_uint8_t *)&ui16local_tempvalue , 
                                     ZB_FALSE);
   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Set local temperature value fail. zcl_status: %d", zcl_status);
   }
}
void CurrentSetpointChangeValue(zb_uint16_t ui16CurrentSetpoint)
{
   zb_zcl_status_t zcl_status;
   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_CURRENT_SETPOINT_CHANGE_ID,
                                    (zb_uint8_t *)&ui16CurrentSetpoint,
                                    ZB_FALSE);
   
   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Setc current set point temperature value fail. zcl_status: %d", zcl_status);
   }

   
   if(ui16CurrentSetpoint != 0xFFFF)
   {
      ui16CurrentTemp = ui16CurrentSetpoint;
   }
   else
   {
      ui16CurrentTemp = 0xFFFF;
   }

}

/**
**function to read/write the occupied heating setpoint 
**Any change in occupied heating value will automatically copied to set point change attribute
**
**/
void OccupiedHeatingSetpoint(zb_uint16_t ui16OccupiedSetpoint)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID,
                                    (zb_uint8_t *)&ui16OccupiedSetpoint,
                                    ZB_FALSE);
   
     
   if(ui16OccupiedSetpoint != 0xFFFF)
   {
      ui16OccupiedHeatSetpoint = ui16OccupiedSetpoint;
      ui16CurrentTemp = ui16OccupiedSetpoint;
      CurrentSetpointChangeValue(ui16CurrentTemp);
   }
   else
   {
      ui16OccupiedHeatSetpoint == 0xFFFF;
   }
   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Set occupied heating setpoint temperature value fail. zcl_status: %d", zcl_status);
   }
}

void ReadOccupiedHeatingSetpoint(zb_uint16_t ui16ReadOccupiedSetpoint)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID,
                                    (zb_uint8_t *)&ui16ReadOccupiedSetpoint,
                                    ZB_FALSE);

   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Set occupied heating setpoint temperature value fail. zcl_status: %d", zcl_status);
   }
}
/**
**function to read/write the unoccupied heating setpoint 
**Any change in unoccupied heating value will automatically copied to set point change attribute
**
**/
void UnOccupiedHeatingSetpoint(zb_uint16_t ui16UnOccupiedSetpoint)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_UNOCCUPIED_HEATING_SETPOINT_ID,
                                    (zb_uint8_t *)&ui16UnOccupiedSetpoint,
                                    ZB_FALSE);
   
   if(ui16UnOccupiedSetpoint != 0xFFFF)
   {
     ui16UnOccupiedHeatSetpoint = ui16UnOccupiedSetpoint;
     ui16CurrentTemp = ui16UnOccupiedSetpoint;
     CurrentSetpointChangeValue(ui16CurrentTemp);
   }
   else
   {
     ui16UnOccupiedHeatSetpoint =  0xFFFF;
   }
   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Set unoccupied heating setpoint temperature value fail. zcl_status: %d", zcl_status);
   }
}

/**
**function to read value of pi heating demand
**Any change in valve position value will be copied to PI heating demand attribute which only read attribute
**
**/
static void PIHeatingDemand (zb_uint8_t ui8PiHeatingDemand)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_PI_HEATING_DEMAND_ID,
                                    &ui8PiHeatingDemand,
                                    ZB_FALSE);
   

   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("read pi heating demand value fail. zcl_status: %d", zcl_status);
   }
}
/**
**function for read/write local temperature calibration
**Any change in local temperature attribute then add this value to D11 and D12 of set temperature command
**
**/
static void LocalTemperatureCalibration(zb_uint8_t ui8localTempCalibration)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_CALIBRATION_ID,
                                    &ui8localTempCalibration,
                                    ZB_FALSE);
   
   ui8LocalTemperatureCalibration = ui8localTempCalibration;

   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("local temperature calibration value fail. zcl_status: %d", zcl_status);
   }
}
/**
**function to read/write the valve position
**Any change in valve position value will be copied to PI heating demand attribute which only read attribute
**
**/
void SetValvePosition(zb_uint8_t ui8ValvePosition)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_SET_VALVE_POSITION_ID,
                                    &ui8ValvePosition,
                                    ZB_FALSE);
   
   PIHeatingDemand(ui8ValvePosition);

   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Set valve position value fail. zcl_status: %d", zcl_status);
   }
}

void SetTRVMode (zb_uint8_t ui8TRVMode)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                    ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                                    ZB_ZCL_ATTR_THERMOSTAT_TRV_MODE_ID,
                                    &ui8TRVMode,
                                    ZB_FALSE);
   
   

   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Set trv mode value fail. zcl_status: %d", zcl_status);
   }
}
/**@brief Function for remaining battery percentage 
 *
 * @param[in]   new_value local temp value
 */
void ReadRemainigBatteryPercentage(zb_uint8_t ui8BatteryPercentage)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                     ZB_ZCL_CLUSTER_ID_POWER_CONFIG, 
                                     ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                     ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_REMAINING_ID, 
                                     &ui8BatteryPercentage , 
                                     ZB_FALSE);
   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Set Battery percentage value fail. zcl_status: %d", zcl_status);
   }
}
/**
**function to read the error status for different valve status 
**Any change in valve status respective error state copied to Error attribute which is read only attribute
**
**/
void ReadErrorStatus(zb_uint8_t ui8ErrorStatus)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                     ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                                     ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                     ZB_ZCL_ATTR_THERMOSTAT_ERROR_ID, 
                                     &ui8ErrorStatus , 
                                     ZB_FALSE);
   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("read error status fail. zcl_status: %d", zcl_status);
   }
}
/**
**function to read/write the flag status for different operation 
**
**
**/
void HostFlagStatus(zb_uint32_t ui32HostFlagsStatus)
{
   zb_zcl_status_t zcl_status;

   zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                     ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                                     ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                     ZB_ZCL_ATTR_THERMOSTAT_HOST_FLAG_ID, 
                                     (zb_uint8_t *)&ui32HostFlagsStatus, 
                                     ZB_FALSE);
   ui32HostflagsData = ui32HostFlagsStatus;

    //Rotate LCD by 180
    if((ui32HostflagsData & 0x000002)== 0x02)
    {    
      boolSetHostflags = false;

      boolSendDeviceConfig = true;
      if((ui8SendDeviceConfig[5] ^ DEVICE_CONFIG_BYTE_3_LCD_ROTATION) & DEVICE_CONFIG_BYTE_3_LCD_ROTATION ) 
      {
        ui8SendDeviceConfig[5] |= DEVICE_CONFIG_BYTE_3_LCD_ROTATION;        
      }
    }
    //LCD in default position
    if((ui32HostflagsData ^ 0x000002) & 0x02 )
    {
      boolSetHostflags = false;
      boolSendDeviceConfig = true;
      if(ui8SendDeviceConfig[5]  & DEVICE_CONFIG_BYTE_3_LCD_ROTATION) 
      {
        ui8SendDeviceConfig[5]  &= ui8SendDeviceConfig[5] ^ DEVICE_CONFIG_BYTE_3_LCD_ROTATION;		        
      }
    }

   if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
   {
      NRF_LOG_INFO("Host flag status fail. zcl_status: %d", zcl_status);
   }
}

/**@brief Callback function for handling ZCL commands.
 *
 * @param[in]   param   Reference to ZigBee stack buffer used to pass received data.
 */
static zb_void_t zcl_device_cb(zb_uint8_t param)
{
    zb_uint16_t                cluster_id;
    zb_uint16_t                attr_id;
    zb_buf_t                       * p_buffer = ZB_BUF_FROM_REF(param);
    zb_zcl_device_callback_param_t * p_device_cb_param =
                     ZB_GET_BUF_PARAM(p_buffer, zb_zcl_device_callback_param_t);

    NRF_LOG_INFO("zcl_device_cb id %hd", p_device_cb_param->device_cb_id);

    /* Set default response value. */
    p_device_cb_param->status = RET_OK;

    switch (p_device_cb_param->device_cb_id)
    {
        case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
               cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
               attr_id = p_device_cb_param->cb_param.set_attr_value_param.attr_id;

             if (cluster_id == ZB_ZCL_CLUSTER_ID_THERMOSTAT)
             {
                  if (attr_id == ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID)
                  {
                      zb_int16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
                      OccupiedHeatingSetpoint(value);
                       boolSetTemperature = true;
                       boolReady = true;
                       boolMCUInterrupt = false; 
                      
                  }
                  else if (attr_id == ZB_ZCL_ATTR_THERMOSTAT_UNOCCUPIED_HEATING_SETPOINT_ID)
                  {
                      zb_int16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
                      UnOccupiedHeatingSetpoint(value);
                       boolSetTemperature = true;
                       boolReady = true;
                       boolMCUInterrupt = false; 
                     
                  }
                  else if (attr_id ==ZB_ZCL_ATTR_THERMOSTAT_CURRENT_SETPOINT_CHANGE_ID)
                  {
                      zb_int16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
                      CurrentSetpointChangeValue(value);
                       boolSetTemperature = true;
                       boolReady = true;
                       boolMCUInterrupt = false; 
                       
                  }
                  else if(attr_id ==ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_CALIBRATION_ID)
                  {
                      zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
                      LocalTemperatureCalibration(value);
                  }
                  else if (attr_id ==ZB_ZCL_ATTR_THERMOSTAT_SET_VALVE_POSITION_ID)
                  {
                      zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
                      SetValvePosition(value);
                  }
                  else if(attr_id == ZB_ZCL_ATTR_THERMOSTAT_HOST_FLAG_ID)
                  {
                     zb_uint32_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data32;
                     HostFlagStatus(value);
                     boolSetHostflags  = true; 
                     boolReady = true;
                     boolMCUInterrupt = false; 
                  }
                  else if(attr_id == ZB_ZCL_ATTR_THERMOSTAT_TRV_MODE_ID)
                  {
                     zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
                     SetTRVMode(value);
                  }
             }
              
          break;


        default:
            p_device_cb_param->status = RET_ERROR;
            break;
    }

    NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
}

/**@brief ZigBee stack event handler.
 *
 * @param[in]   param   Reference to ZigBee stack buffer used to pass arguments (signal).
 */
void zboss_signal_handler(zb_uint8_t param)
{
    zb_zdo_app_signal_hdr_t  * p_sg_p = NULL;
    zb_zdo_app_signal_type_t   sig    = zb_get_app_signal(param, &p_sg_p);
    zb_ret_t                   status = ZB_GET_APP_SIGNAL_STATUS(param);
    zb_bool_t                  comm_status;

    switch (sig)
    {
        case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
        case ZB_BDB_SIGNAL_DEVICE_REBOOT:
            if (status == RET_OK)
            {
                NRF_LOG_INFO("Joined network successfully");
                bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);                
                boolSetCommand  = true; 
                boolReady = true;
                boolGetStatus = true;
            }
            else
            {
                NRF_LOG_ERROR("Failed to join network. Status: %d", status);
                bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                ZB_COMM_STATUS_CHECK(comm_status);
            }
            break;

        case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
            if (status != RET_OK)
            {
                NRF_LOG_WARNING("Production config is not present or invalid");
            }
            break;

        case ZB_COMMON_SIGNAL_CAN_SLEEP:
            {
                zb_sleep_now(); //when receiving the signal ZB_COMMON_SIGNAL_CAN_SLEEP call sleep_now()
            }
            break;

        case ZB_ZDO_SIGNAL_LEAVE:
            if (status == RET_OK)
            {
                bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);

                zb_zdo_signal_leave_params_t * p_leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_leave_params_t);
                NRF_LOG_INFO("Network left. Leave type: %d", p_leave_params->leave_type);
            }
            else
            {
                NRF_LOG_ERROR("Unable to leave network. Status: %d", status);
            }
            break;

        default:
            /* Unhandled signal. For more information see: zb_zdo_app_signal_type_e and zb_ret_e */
            NRF_LOG_INFO("Unhandled signal %d. Status: %d", sig, status);
            break;
    }

    if (param)
    {
        ZB_FREE_BUF_BY_REF(param);
    }
}


/**@brief Function for application main entry.
 */
void main(void)
{
    zb_ret_t       zb_err_code;
    zb_ieee_addr_t ieee_addr;

    nrf_delay_ms(1500);

    /* Initialize logging system and GPIOs. */
    timer_init();
    log_init();

    leds_init();

    Uart_Init_Func();    

    timer_config_func();

    ulp_input_pin_configuration();
 
    Flashinitialization();

    /* Set ZigBee stack logging level and traffic dump subsystem. */
    ZB_SET_TRACE_LEVEL(ZIGBEE_TRACE_LEVEL);
    ZB_SET_TRACE_MASK(ZIGBEE_TRACE_MASK);
    ZB_SET_TRAF_DUMP_OFF();

    /* Initialize Zigbee stack. */
    ZB_INIT("thermostat");

    /* Set device address to the value read from FICR registers. */
    zb_osif_get_ieee_eui64(ieee_addr);
    zb_set_long_address(ieee_addr);

    /* Set static long IEEE address. */
    zb_set_network_ed_role(IEEE_CHANNEL_MASK);
    zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);

    zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
    zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
    zb_set_rx_on_when_idle(ZB_FALSE); // This enables sleepy behavior and makes your device act as a Sleepy End Device.

    zb_set_node_descriptor_manufacturer_code(ZB_ZCL_MANF_CODE);

    /* Initialize application context structure. */
    UNUSED_RETURN_VALUE(ZB_MEMSET(&m_dev_ctx, 0, sizeof(m_dev_ctx)));

    /* Register callback for handling ZCL commands. */
    ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);

    /* Register thermostat device context (endpoints). */
    ZB_AF_REGISTER_DEVICE_CTX(&thermostat_ctx);

    thermostat_clusters_attr_init();
    /** Start Zigbee Stack. */
    zb_err_code = zboss_start();
    ZB_ERROR_CHECK(zb_err_code);   
     
   
    CommandBootloader();  //get bootloader command 

    while(1)
    {
       zboss_main_loop_iteration();
       UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());

        CommunicationStateExecution();   //MCU and NP communication state     
        DataProcessing();                //Flag bit processing
        UARTStateStateMachine();    
    }
}


/**
 * @}
 */
