/**
 * 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_ha_dimmable_light.h"
#include "zb_error_handler.h"
#include "zb_nrf52840_internal.h"
#include "zigbee_helpers.h"

#include "bsp.h"
#include "boards.h"
#include "app_pwm.h"
#include "app_timer.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "nrf_drv_gpiote.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_saadc.h"
#include "nrf_delay.h"

//flash include files 
#include "nrf_fstorage.h"
#include "nrf_fstorage_nvmc.h"

#define MAX_CHILDREN                      10                                    /**< The maximum amount of connected devices. Setting this value to 0 disables association to this device.  */
//              /**< Scan only one, predefined channel to find the coordinator. */
#define IEEE_CHANNEL_MASK                  (ZB_TRANSCEIVER_ALL_CHANNELS_MASK)
#define HA_DIMMABLE_LIGHT_ENDPOINT        10                                    /**< Device endpoint, used to receive light controlling commands. */
#define ERASE_PERSISTENT_CONFIG           ZB_FALSE                              /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. */


/* Basic cluster attributes initial values. */
#define BULB_INIT_BASIC_APP_VERSION       01                                    /**< Version of the application software (1 byte). */
#define BULB_INIT_BASIC_STACK_VERSION     10                                    /**< Version of the implementation of the ZigBee stack (1 byte). */
#define BULB_INIT_BASIC_HW_VERSION        11                                    /**< Version of the hardware of the device (1 byte). */
#define BULB_INIT_BASIC_MANUF_NAME        "Nordic"                              /**< Manufacturer name (32 bytes). */
#define BULB_INIT_BASIC_MODEL_ID          "Dimable_Light_v0.1"                  /**< Model number assigned by manufacturer (32-bytes long string). */
#define BULB_INIT_BASIC_DATE_CODE         "20180416"                            /**< First 8 bytes specify the date of manufacturer of the device in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific. */
#define BULB_INIT_BASIC_POWER_SOURCE      ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE   /**< Type of power sources available for the device. For possible values see section 3.2.2.2.8 of ZCL specification. */
#define BULB_INIT_BASIC_LOCATION_DESC     "Office desk"                         /**< Describes the physical location of the device (16 bytes). May be modified during commisioning process. */
#define BULB_INIT_BASIC_PH_ENV            ZB_ZCL_BASIC_ENV_UNSPECIFIED          /**< Describes the type of physical environment. For possible values see section 3.2.2.2.10 of ZCL specification. */

#define IDENTIFY_MODE_ENTER_BUTTON        BSP_BOARD_BUTTON_0                    /**< Enter the Bulb into the Identify mode. */
#ifdef  BOARD_PCA10059                                                          /**< If it is Dongle */
#define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_0                       /**< LED indicating that light switch successfully joind ZigBee network. */
#else
#define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_3                       /**< LED indicating that light switch successfully joind ZigBee network. */
#endif


/* Declare endpoint for Dimmable Light device with scenes. */
#define ZB_HA_DECLARE_LIGHT_EP(ep_name, ep_id, cluster_list)                         \
  ZB_ZCL_DECLARE_HA_DIMMABLE_LIGHT_SIMPLE_DESC(ep_name, ep_id,                       \
    ZB_HA_DIMMABLE_LIGHT_IN_CLUSTER_NUM, ZB_HA_DIMMABLE_LIGHT_OUT_CLUSTER_NUM);      \
  ZBOSS_DEVICE_DECLARE_REPORTING_CTX(reporting_info## device_ctx_name,               \
                                     ZB_HA_DIMMABLE_LIGHT_REPORT_ATTR_COUNT);        \
  ZBOSS_DEVICE_DECLARE_LEVEL_CONTROL_CTX(cvc_alarm_info## device_ctx_name,           \
                                         ZB_HA_DIMMABLE_LIGHT_CVC_ATTR_COUNT);       \
  ZB_AF_DECLARE_ENDPOINT_DESC(ep_name, ep_id, ZB_AF_HA_PROFILE_ID,                   \
                              0,     \
                              NULL,                 \
                              ZB_ZCL_ARRAY_SIZE(cluster_list, zb_zcl_cluster_desc_t),\
                              cluster_list,                                          \
                              (zb_af_simple_desc_1_1_t*)&simple_desc_##ep_name,      \
                              ZB_HA_DIMMABLE_LIGHT_REPORT_ATTR_COUNT,                \
                              reporting_info## device_ctx_name,                      \
                              ZB_HA_DIMMABLE_LIGHT_CVC_ATTR_COUNT,                   \
                              cvc_alarm_info## device_ctx_name)

#if !defined ZB_ROUTER_ROLE
#error Define ZB_ROUTER_ROLE to compile light bulb (Router) source code.
#endif

/********************Custom MACRO Pin Mapping*******************************/
#define ZERO_CROSS_DETECTION       NRF_GPIO_PIN_MAP(0,6)      //ZCD pin 
#define DIMMER_TRIGGER             NRF_GPIO_PIN_MAP(0,8)      //Trigger pin
#define EXTSW1_CONTROL             BSP_BUTTON_1         //ExtSW1 pin

#define EXTSW2_CONTROL             NRF_GPIO_PIN_MAP(0,26)     //EXtSW2 pin

#define KEY_UP                     NRF_GPIO_PIN_MAP(1,10)     //Up pin
#define KEY_DOWN                   NRF_GPIO_PIN_MAP(1,13)     //Down pin

//#define KEY_LEARN                  NRF_GPIO_PIN_MAP(0,24)     //Learn pin
#define OPTIONAL1_KEY              NRF_GPIO_PIN_MAP(1,15)     //Optional1 pin
#define OPTIONAL2_KEY              NRF_GPIO_PIN_MAP(0,2)      //Optional2 pin
#define GREEN_LED                  BSP_BOARD_LED_0 //Green led pin 
#define RED_LED                    BSP_BOARD_LED_2 //Red led pin

//MACROS brightness 
#define HALFCYCLE_10MSTIME          10000       //10msec for half cycle time 
#define MAX_DUTYCYCLE               9000       //max duty cycle 9msec
#define MIN_ADC_VAL                 78         //minimum adc value with repsective capacitor minimum voltage 

//Flash related MACROS 
#define FLASH_START_ADDRESS           0x3F000
#define FLASH_END_ADDRESS             0x3FFFF

void timer2_Configuration (void);       //timer 2 configured as duty cycle timer 
void timer2_DimmingControlling_tme(uint32_t ui32Timer2Dutycycle); 

void timer1_Configuration (void);       //timer 1 configured as fixed timer for negative cycle 
void timer1_fixedtimeOperation (uint32_t ui32fixedtime);


/* Basic cluster attributes. */
typedef struct
{
    zb_uint8_t zcl_version;
    zb_uint8_t app_version;
    zb_uint8_t stack_version;
    zb_uint8_t hw_version;
    zb_char_t  mf_name[32];
    zb_char_t  model_id[32];
    zb_char_t  date_code[16];
    zb_uint8_t power_source;
    zb_char_t  location_id[17];
    zb_uint8_t ph_env;
    zb_char_t  sw_ver[17];
} bulb_device_basic_attr_t;

/* Identify cluster attributes. */
typedef struct
{
    zb_uint16_t identify_time;
} bulb_device_identify_attr_t;

/* ON/Off cluster attributes. */
typedef struct
{
    zb_bool_t   on_off;
    zb_bool_t   global_scene_ctrl;
    zb_uint16_t on_time;
    zb_uint16_t off_wait_time;
} bulb_device_on_off_attr_t;

/* Level Control cluster attributes. */
typedef struct
{
    zb_uint8_t  current_level;
    zb_uint16_t remaining_time;
} bulb_device_level_control_attr_t;

/* Scenes cluster attributes. */
typedef struct
{
    zb_uint8_t  scene_count;
    zb_uint8_t  current_scene;
    zb_uint8_t  scene_valid;
    zb_uint8_t  name_support;
    zb_uint16_t current_group;
} bulb_device_scenes_attr_t;

/* Groups cluster attributes. */
typedef struct
{
    zb_uint8_t name_support;
} bulb_device_groups_attr_t;

/* Main application customizable context. Stores all settings and static values. */
typedef struct
{
    bulb_device_basic_attr_t         basic_attr;
    bulb_device_identify_attr_t      identify_attr;
    bulb_device_scenes_attr_t        scenes_attr;
    bulb_device_groups_attr_t        groups_attr;
    bulb_device_on_off_attr_t        on_off_attr;
    bulb_device_level_control_attr_t level_control_attr;
} bulb_device_ctx_t;

/* constant declaration -----------------------------------------------*/
const nrf_drv_timer_t TIMER_1 = NRF_DRV_TIMER_INSTANCE(2);  // Created instance as timer 1
const nrf_drv_timer_t TIMER_2 = NRF_DRV_TIMER_INSTANCE(4);  // Created instance as timer 2

/*************GLOBAL VATIABLES***************************************/
uint32_t time2_ticks;
uint32_t ui32DimmerONTime = 0;
uint32_t CurrentDutyCycle = 0;
uint32_t ui32fixedtime = 0;
uint32_t ui32Brightness = 0; 

//case operation flags
bool boolIgnorelongpress = false;
bool bool2WayButtonConfig = false;
bool boolRelayOperation = false;
bool boolIgnoreExtSw1OnOff = false; //to ignore button ExtSw1 
bool boolIgnoreExtSw2OnOff = false; //to ignore button ExtSw2 

//push button config variables
uint16_t ui8PushbuttonStatusCount = 0;
uint8_t ui8Pushbuttonstatus = 0;

bool boolpushbuttonStatus = false;
bool boolpushbuttonContinue = false;
bool boolBrightnesslevelcontrol = false;
bool boolNextZCDProcess = false;

//button_2 global variables
uint16_t ui16PushButton2Count = 0;
uint8_t ui8PushButton2status = 0;
bool boolPushButton2Status = false;
bool boolPushButton2Continue = false;
bool boolPushButton2BrightnessControl = false;

//button_3 global variables
uint16_t ui16PushButton3Count = 0;
uint8_t ui8PushButton3status = 0;
bool boolPushButton3Status = false;
bool boolPushButton3Continue = false;
bool boolPushButton3BrightnessControl = false;

//external button2 i.e ExtSW2 pin variables 
uint8_t  ui8ExtSW2Status = 0;


//Optional1 and Optional2 push button variables
uint32_t ui32SaveDataFlash = 0;
uint8_t ui8blink = 0;

typedef enum OperationalCase
{
  CASE_NONE = 0,
  CASE_1,         //Tactile switches would be connected as external switches and would be used to toggle and Inc/Dec Dimmer brightness 
  CASE_2,         //Two Way switch would be connected to the external switches and would be used to toggle the dimmer state.
  CASE_3,        // TBD
  MAX_CASE
}OpCase;

OpCase ExternalSwitchOpCase = CASE_NONE; 
uint8_t ui8OptionalKey2Counter = 0;

bool boolOperationCaseSelection = false;

//SAADC/ADC variables
uint16_t ui16CurrentADCValue = 255; 
uint32_t ui32DutyCycle100 = MAX_DUTYCYCLE;

//Flag to monitor ADC value comparision with w. r. t. 0.7V while initial sequence implmentation
bool boolADCComparisonComplete = true;
//Monitors ADC Reading while initial sequence implmentation
bool boolADCReadingComplete = false;
//Flag indicating initial sequence operation or normal operation
bool boolInitialSequenceMeasurement = true;

bool boolSetInit30 = false;
float Val = 0, Val2=0;
uint32_t Result =0;
static nrf_saadc_value_t adc_buf[1];
/*************************END****************************************/


static bulb_device_ctx_t m_dev_ctx;

ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_dev_ctx.identify_attr.identify_time);


ZB_ZCL_DECLARE_GROUPS_ATTRIB_LIST(groups_attr_list, &m_dev_ctx.groups_attr.name_support);

ZB_ZCL_DECLARE_SCENES_ATTRIB_LIST(scenes_attr_list,
                                  &m_dev_ctx.scenes_attr.scene_count,
                                  &m_dev_ctx.scenes_attr.current_scene,
                                  &m_dev_ctx.scenes_attr.current_group,
                                  &m_dev_ctx.scenes_attr.scene_valid,
                                  &m_dev_ctx.scenes_attr.name_support);

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);

/* On/Off cluster attributes additions data */
ZB_ZCL_DECLARE_ON_OFF_ATTRIB_LIST_EXT(on_off_attr_list,
                                      &m_dev_ctx.on_off_attr.on_off,
                                      &m_dev_ctx.on_off_attr.global_scene_ctrl,
                                      &m_dev_ctx.on_off_attr.on_time,
                                      &m_dev_ctx.on_off_attr.off_wait_time);

ZB_ZCL_DECLARE_LEVEL_CONTROL_ATTRIB_LIST(level_control_attr_list,
                                         &m_dev_ctx.level_control_attr.current_level,
                                         &m_dev_ctx.level_control_attr.remaining_time);

ZB_HA_DECLARE_DIMMABLE_LIGHT_CLUSTER_LIST(dimmable_light_clusters,
                                          basic_attr_list,
                                          identify_attr_list,
                                          groups_attr_list,
                                          scenes_attr_list,
                                          on_off_attr_list,
                                          level_control_attr_list);

ZB_HA_DECLARE_LIGHT_EP(dimmable_light_ep,
                       HA_DIMMABLE_LIGHT_ENDPOINT,
                       dimmable_light_clusters);

ZB_HA_DECLARE_DIMMABLE_LIGHT_CTX(dimmable_light_ctx,
                                 dimmable_light_ep);

/*****************Flash functions and callback start*************************************/

//Flash related callback function initialization
static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt);

//structure defines the callback function, flash start and end address 
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) =
{
    /* Set a handler for fstorage events. */
    .evt_handler = fstorage_evt_handler,

    /* These below are the boundaries of the flash space assigned to this instance of fstorage.
     * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
     * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
     * last page of flash available to write data. */
    .start_addr = FLASH_START_ADDRESS,
    .end_addr   = FLASH_END_ADDRESS,
};
//fstorage event handler/callback function 
static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
{
    if (p_evt->result != NRF_SUCCESS)
    {
        NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation.");
        return;
    }

    switch (p_evt->id)
    {
        case NRF_FSTORAGE_EVT_WRITE_RESULT:
        {
            NRF_LOG_INFO("--> Event received: wrote %d bytes at address 0x%x.",
                         p_evt->len, p_evt->addr);
        } break;

        case NRF_FSTORAGE_EVT_ERASE_RESULT:
        {
            NRF_LOG_INFO("--> Event received: erased %d page from address 0x%x.",
                         p_evt->len, p_evt->addr);
        } break;

        default:
            break;
    }
}

//flash initialization function 
static void flash_initialization(void)
{
    ret_code_t     error_code;
    nrf_fstorage_api_t * p_fs_api;

  #ifdef SOFTDEVICE_PRESENT
      NRF_LOG_INFO("SoftDevice is present.");
      NRF_LOG_INFO("Initializing nrf_fstorage_sd implementation...");
      /* Initialize an fstorage instance using the nrf_fstorage_sd backend.
       * nrf_fstorage_sd uses the SoftDevice to write to flash. This implementation can safely be
       * used whenever there is a SoftDevice, regardless of its status (enabled/disabled). */
      p_fs_api = &nrf_fstorage_sd;
  #else
      NRF_LOG_INFO("SoftDevice not present.");
      NRF_LOG_INFO("Initializing nrf_fstorage_nvmc implementation...");
      /* Initialize an fstorage instance using the nrf_fstorage_nvmc backend.
       * nrf_fstorage_nvmc uses the NVMC peripheral. This implementation can be used when the
       * SoftDevice is disabled or not present.
       *
       * Using this implementation when the SoftDevice is enabled results in a hardfault. */
      p_fs_api = &nrf_fstorage_nvmc;
  #endif

    error_code = nrf_fstorage_init(&fstorage, p_fs_api, NULL);
    APP_ERROR_CHECK(error_code);
}

/*****************Flash functions and callback end**************************************/

/**@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();
}

/*********Brightness set command from Alexa or App*******************************************/
/**@brief Sets brightness of LED
 *
 * @param[in] brightness_level Brightness level, allowed values 0 ... 255, 0 - turn off, 255 - full brightness
 */
static void light_bulb_onboard_set_brightness(zb_uint8_t brightness_level)
{
    
    /* ZigBee level control cluster uses values from 0 up to 255. */
     //Convert brigthness level values as per 0 to 100 range 
     ui32DimmerONTime = ((brightness_level * 100)/ 255);
     //set brightness level to 100% Max 
     CurrentDutyCycle = ((((ui32DimmerONTime * 0.75) + 25) * ui32DutyCycle100)/100);     
}


/**@brief Sets brightness of bulb luminous executive element
 *
 * @param[in] brightness_level Brightness level, allowed values 0 ... 255, 0 - turn off, 255 - full brightness
 */
static void light_bulb_set_brightness(zb_uint8_t brightness_level)
{
    light_bulb_onboard_set_brightness(brightness_level);
}

/**@brief Function for setting the light bulb brightness.
  *
  * @param[in]   new_level   Light bulb brightness value.
 */
static void level_control_set_value(zb_uint16_t new_level)
{
    NRF_LOG_INFO("Set level value: %i", new_level);

    ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,                                       
                         ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL,            
                         ZB_ZCL_CLUSTER_SERVER_ROLE,                 
                         ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, 
                         (zb_uint8_t *)&new_level,                                       
                         ZB_FALSE);                                  

    /* According to the table 7.3 of Home Automation Profile Specification v 1.2 rev 29, chapter 7.1.3. */
    if (new_level == 0)
    {
        zb_uint8_t value = ZB_FALSE;
        ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT, 
                             ZB_ZCL_CLUSTER_ID_ON_OFF,    
                             ZB_ZCL_CLUSTER_SERVER_ROLE,  
                             ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
                             &value,                        
                             ZB_FALSE);                   
    }
    else
    {
        zb_uint8_t value = ZB_TRUE;
        ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT, 
                             ZB_ZCL_CLUSTER_ID_ON_OFF,    
                             ZB_ZCL_CLUSTER_SERVER_ROLE,  
                             ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
                             &value,                        
                             ZB_FALSE);
    }

    light_bulb_set_brightness(new_level);
}


/**@brief Function for turning ON/OFF the light bulb.
 *
 * @param[in]   on   Boolean light bulb state.
 */
static void on_off_set_value(zb_bool_t on)
{
    NRF_LOG_INFO("Set ON/OFF value: %i", on);

    ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT, 
                         ZB_ZCL_CLUSTER_ID_ON_OFF,    
                         ZB_ZCL_CLUSTER_SERVER_ROLE,  
                         ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
                         (zb_uint8_t *)&on,                        
                         ZB_FALSE);


    if (on)
    {       
        level_control_set_value(m_dev_ctx.level_control_attr.current_level);  
        boolIgnorelongpress = false;
        boolBrightnesslevelcontrol = false; //forcefully set the flag flase so next cycle of long press should be increment               
    }
    else
    {
        light_bulb_set_brightness(0U);  
        CurrentDutyCycle = 0;
        boolIgnorelongpress = true; 
    }

}



/**@brief Function for initializing LEDs and a single PWM channel.
 */
static void leds_buttons_init(void)
{
    /* Initialize all LEDs*/
    /* Configure board. */
    bsp_board_init(BSP_INIT_LEDS);
    bsp_board_led_on(RED_LED); //power on process turn Off RED_LED
    
}

/**@brief Function for initializing all clusters attributes.
 */
static void bulb_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   = BULB_INIT_BASIC_APP_VERSION;
    m_dev_ctx.basic_attr.stack_version = BULB_INIT_BASIC_STACK_VERSION;
    m_dev_ctx.basic_attr.hw_version    = BULB_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,
                          BULB_INIT_BASIC_MANUF_NAME,
                          ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MANUF_NAME));

    ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.model_id,
                          BULB_INIT_BASIC_MODEL_ID,
                          ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MODEL_ID));

    ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.date_code,
                          BULB_INIT_BASIC_DATE_CODE,
                          ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_DATE_CODE));

    m_dev_ctx.basic_attr.power_source = BULB_INIT_BASIC_POWER_SOURCE;

    ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.location_id,
                          BULB_INIT_BASIC_LOCATION_DESC,
                          ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_LOCATION_DESC));


    m_dev_ctx.basic_attr.ph_env = BULB_INIT_BASIC_PH_ENV;

    /* Identify cluster attributes data */
    m_dev_ctx.identify_attr.identify_time = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;

    /* On/Off cluster attributes data */
    m_dev_ctx.on_off_attr.on_off = (zb_bool_t)ZB_ZCL_ON_OFF_IS_ON;

    m_dev_ctx.level_control_attr.current_level  = ZB_ZCL_LEVEL_CONTROL_LEVEL_MAX_VALUE;
    m_dev_ctx.level_control_attr.remaining_time = ZB_ZCL_LEVEL_CONTROL_REMAINING_TIME_DEFAULT_VALUE;

    ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT, 
                         ZB_ZCL_CLUSTER_ID_ON_OFF,    
                         ZB_ZCL_CLUSTER_SERVER_ROLE,  
                         ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
                         (zb_uint8_t *)&m_dev_ctx.on_off_attr.on_off,                        
                         ZB_FALSE);                   

    ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,                                       
                         ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL,            
                         ZB_ZCL_CLUSTER_SERVER_ROLE,                 
                         ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, 
                         (zb_uint8_t *)&m_dev_ctx.level_control_attr.current_level,                                       
                         ZB_FALSE);                                  
}

/**@brief Function which tries to sleep down the MCU 
 *
 * Function which sleeps the MCU on the non-sleepy End Devices to optimize the power saving.
 * The weak definition inside the OSIF layer provides some minimal working template
 */
zb_void_t zb_osif_go_idle(zb_void_t)
{
    //TODO: implement your own logic if needed
    zb_osif_wait_for_event();
}

/**@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_uint8_t                       cluster_id;
    zb_uint8_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_LEVEL_CONTROL_SET_VALUE_CB_ID:
            NRF_LOG_INFO("Level control setting to %d", p_device_cb_param->cb_param.level_control_set_value_param.new_value);
            level_control_set_value(p_device_cb_param->cb_param.level_control_set_value_param.new_value);
            break;

        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_ON_OFF)
            {
                uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;

                NRF_LOG_INFO("on/off attribute setting to %hd", value);
                if (attr_id == ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID)
                {
                    on_off_set_value((zb_bool_t) value);
                }
            }
            else if (cluster_id == ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL)
            {
                uint16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;

                NRF_LOG_INFO("level control attribute setting to %hd", value);
                if (attr_id == ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID)
                {
                    level_control_set_value(value);
                }
            }
            else
            {
                /* Other clusters can be processed here */
                NRF_LOG_INFO("Unhandled cluster attribute id: %d", cluster_id);
            }
            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);
            }
            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_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);
    }
}


/***************************SAADC Configuration Start*********************************************/

/**@brief Function for handling the ADC interrupt.
 *
 * @details  This function will fetch the conversion result from the ADC, convert the value into
 *           percentage and send it to peer.
 */
void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        
        uint32_t          err_code;

        ui16CurrentADCValue = p_event->data.done.p_buffer[0];  

        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
        APP_ERROR_CHECK(err_code);
        
        //Set Read Completed flag as Read ADC event is serviced
        boolADCReadingComplete = true;
      
    }
}
/* This Initial sequence to carried out to measure the intensity level for light controlling 
*  with respect to voltage level at input capacitor.
*
*/
static void GetADCValue(void)
{
    ret_code_t err_code;

    //Trigger SAADC/ADC module to sample the ADC Value and Get ADC value w. r. t capacitor Voltage
    err_code = nrf_drv_saadc_sample(); 
    APP_ERROR_CHECK(err_code);
    //Reading evnt triggered so reset flag which will be set when ADC value received
    boolADCReadingComplete = false;
    //Reset compariosn flag true new ADC read event triggred
    boolADCComparisonComplete =false;
}

static void InitialSequence(void)
{
    //Check if ADC Value is Read in callback
    if(boolADCReadingComplete)
    {
      //Check if Capacitor voltage has dropped below 0.7V
      if(ui16CurrentADCValue < MIN_ADC_VAL)
      {
        //Save the Maximum Duty cycle value 
        ui32DutyCycle100 = ui32Brightness;
        //Update the Duty cycle variable in order adjust values while command received from Alexa          
        on_off_set_value(0U);
        ui32DimmerONTime = 0;
        //Set Boolean flag to set bulb on 30% for initial sequence
        boolSetInit30 = true;
        //Indication that intial sequence calculation is completed
        boolInitialSequenceMeasurement = false;
      }
      //Set compariosn flag true inorder to increment brightness and trigger new ADC read event
      boolADCComparisonComplete = true;
      //As read event not triggered yet reset flag
      boolADCReadingComplete = false;
    }
}

/**@brief Function for configuring ADC to do capacitor voltage conversion.
 */
static void adc_configure(void)
{
    ret_code_t err_code;
    nrf_drv_saadc_config_t saadc_config;
    saadc_config.resolution = NRF_SAADC_RESOLUTION_8BIT;   //8 bit resolution
    saadc_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
    
    err_code = nrf_drv_saadc_init(&saadc_config, saadc_event_handler);
    APP_ERROR_CHECK(err_code);
    
   //singale shot and channel config 
   //If input range is 0 to 2.26V then set reference as VDD/4 and gain as 1/3
   nrf_saadc_channel_config_t channel_config;
   channel_config.reference = NRF_SAADC_REFERENCE_VDD4;
   channel_config.gain = NRF_SAADC_GAIN1_4;
   channel_config.acq_time = NRF_SAADC_ACQTIME_10US;
   channel_config.mode = NRF_SAADC_MODE_SINGLE_ENDED;
   channel_config.pin_n = NRF_SAADC_INPUT_DISABLED; 
   channel_config.pin_p = NRF_SAADC_INPUT_AIN2;
   channel_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
   channel_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;

    err_code = nrf_drv_saadc_channel_init(2, &channel_config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(&adc_buf[0], 1);
    APP_ERROR_CHECK(err_code);
}

/***************************SAADC Configuration End*********************************************/

/***************************ZCD pin handler functions Start*********************************************/
void zcd_in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) //ZCD Interrupt Handler Routine
{
     if(CurrentDutyCycle == 0)  //if the duty cycle is zero then enable ZCD do not disable it 
     {
        nrf_drv_gpiote_in_event_enable(ZERO_CROSS_DETECTION, true);
     }
     else
     {
       //disable ZCD event 
       nrf_drv_gpiote_in_event_disable(ZERO_CROSS_DETECTION);
     }    
    //ADC Measurement and Computation of 100% value based on capitor voltage on
    //every Power ON Sequence.
    
    if(boolInitialSequenceMeasurement)
    {
         //Keep Incrementing the BULB Brightness untill ADC input is above 0.5V
         //Once it is equal or below 0.5V stop the initial sequence and comntinue with normal operation 
         //Also if maximum brightness range is reached then also stop intial sequence
         if((boolADCComparisonComplete) && (ui32Brightness < ui32DutyCycle100))
         {
            ui32Brightness += 10;            
            //Trigger read ADC event
            GetADCValue();
         }
         else if(ui32Brightness >= ui32DutyCycle100)
         {
            //If the capacitor voltage doesnt drops below 0.7V then the brightnees should inmcrease 
            //the maximum allowed value(i.e., 10000) 
            //Once Brightness value reaches maximum allowed level stops the initial sequence
            //and update the required variables
            boolSetInit30 = true;
            boolADCComparisonComplete = false;
            boolInitialSequenceMeasurement = false;
            ui32Brightness = MAX_DUTYCYCLE;
            ui32DutyCycle100 = ui32Brightness;
            CurrentDutyCycle = ui32DutyCycle100;           
            on_off_set_value(0U);
            ui32DimmerONTime = 0;
         }
         else
         {
            
         }
    }
    else
    {
     //Positive cycle operation
     //Computation of Ramp up and Ramp down during brightness change
      if(CurrentDutyCycle != ui32Brightness)
      {
        if(ui32Brightness < CurrentDutyCycle)         //ui32Brightness is the current brightness value that is compared with user set value
        {
            ui32Brightness += 150;	 	//increment brightness
            if(ui32Brightness >= ui32DutyCycle100)        //the maximum duty cycle is 10msec
            {
              ui32Brightness = ui32DutyCycle100;	
            }
        }
        if(ui32Brightness > CurrentDutyCycle)
        {
            ui32Brightness -= 150;	 	 //decrement brightness
            if(ui32Brightness <= 0)
            {
               ui32Brightness = 0;
            }
        }
      }
    }
             
       //start timer1 for 10msec timer to estimate negative cycle start
       timer1_fixedtimeOperation(HALFCYCLE_10MSTIME);      //timer 1 start for 10msec

       if(ui32Brightness != 0) //User has turned off the light
       {         
          if(ui32Brightness >= ui32DutyCycle100) //duty cycle is more than 9ms
           {
             timer2_DimmingControlling_tme(ui32DutyCycle100);  //timer 2 started for brightness control 
             nrf_gpio_pin_write(DIMMER_TRIGGER,1);     //when duty cycle is greater than 0 set trigger pin HIGH 
           }
           else
           {
             timer2_DimmingControlling_tme(ui32Brightness);  //timer 2 started for brightness control
             nrf_gpio_pin_write(DIMMER_TRIGGER,1);     //when duty cycle is greater than 0 set trigger pin HIGH
           }
       }
       if(ui32DimmerONTime == 0)
       {
          nrf_gpio_pin_write(DIMMER_TRIGGER,0);    //when duty cycle is 0 set trigger pin LOW
          ui32Brightness = 0;
          if(boolSetInit30)
          {
            Val = (ui32DutyCycle100*100)/ui32DutyCycle100;
            Val2 = ((Val*255)/100);
            Result = (uint32_t)((Val2*30)/100);
            boolSetInit30 = false;
            m_dev_ctx.level_control_attr.current_level = Result;
            level_control_set_value(m_dev_ctx.level_control_attr.current_level);
            nrf_drv_gpiote_in_event_enable(ZERO_CROSS_DETECTION, true);
          }                    
       }
 
}
/***************************ZCD pin handler functions End*********************************************/

/***************************Button1 pin handler functions Start*********************************************/
void button_in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    //controlling logic using button press interrupt
     boolpushbuttonStatus = true; // if the push button press detect then set flag true
     boolBrightnesslevelcontrol = !boolBrightnesslevelcontrol;   //toggle brightness control flag to increment/decrement level accordingly.
     ui8PushbuttonStatusCount = 0;  

    if(bool2WayButtonConfig)
    {
      if(nrf_gpio_pin_read(EXTSW1_CONTROL))
      {
        nrf_drv_gpiote_in_event_disable(EXTSW1_CONTROL);
        //function to toggle the LED current state
        if(CurrentDutyCycle == 0)
        {                        
            level_control_set_value(m_dev_ctx.level_control_attr.current_level);
            boolIgnorelongpress = false;
        }
        else
        {
             on_off_set_value(0U);                    
             ui32DimmerONTime = 0;
             boolIgnorelongpress = true;  
        } 
        nrf_drv_gpiote_in_event_enable(EXTSW2_CONTROL,true); 
      }
    }
}
/***************************Button1 pin handler functions End*********************************************/

/***************************Button6 pin handler functions Start*********************************************/
void extsw2_in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
     boolpushbuttonStatus = true; // if the extsw2 press detect then set flag true
     boolBrightnesslevelcontrol = !boolBrightnesslevelcontrol; //toggle brightness control flag to increment/decrement level accordingly.    
     ui8PushbuttonStatusCount = 0; 
      
      if(bool2WayButtonConfig)
      { 
         if(nrf_gpio_pin_read(EXTSW2_CONTROL))
         {
            nrf_drv_gpiote_in_event_disable(EXTSW2_CONTROL);
            //function to toggle the LED current state
            if(CurrentDutyCycle == 0)
            {                        
                level_control_set_value(m_dev_ctx.level_control_attr.current_level);
                boolIgnorelongpress = false;
            }
            else
            {
                 on_off_set_value(0U);                    
                 ui32DimmerONTime = 0;
                 boolIgnorelongpress = true;  
            }
            nrf_drv_gpiote_in_event_enable(EXTSW1_CONTROL,true); 
         }
      }

      if(boolRelayOperation)
      {
        if(!boolIgnoreExtSw2OnOff)
        {
          //when ExtSw2 is detected
          if(nrf_gpio_pin_read(EXTSW2_CONTROL))
          {
            if(CurrentDutyCycle == 0)
            {  
              boolBrightnesslevelcontrol = false; //forcefully set the flag flase so next cycle of long press should be increment         
              level_control_set_value(m_dev_ctx.level_control_attr.current_level);
              boolIgnorelongpress = false;   //Reset the flag to detect Up_key and Down_key long press
              boolIgnoreExtSw1OnOff = true;  //while executing Case3 mode and Dimmer On from ExtSw2 input set this flag so that we can ignore ExtSw1 On/Off
            }
          }
          else
          {
             //Off the Dimmer
             on_off_set_value(0U);                    
             ui32DimmerONTime = 0;
             boolIgnorelongpress = true;     //When Off then ignore Up_key and Down_key long press
             boolIgnoreExtSw1OnOff = false;  //while executing Case3 mode and Dimmer Off then accept input from ExtSw2 and ExtSw1
          }
        }
      }
}     
/***************************Button6 pin handler functions End*********************************************/

/***************************Button2 pin handler functions Start*********************************************/
void button2_in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    //button_2 pressed turn ON the LED and Increment the brightness
      boolPushButton2Status = true; //if the push button_2 press detect then set flag
      boolPushButton2BrightnessControl = true;
}
/***************************Button2 pin handler functions End*********************************************/

/***************************Button3 pin handler functions Start*********************************************/
void button3_in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    //button_3 pressed turn OFF the LED and Decrement the brightness
      boolPushButton3Status = true; //if the push button_2 press detect then set flag
      boolPushButton3BrightnessControl = true;
}     
/***************************Button3 pin handler functions End*********************************************/

/*****************************External Switch 2 Configuration functions*********************************/
static void ExternalSwitch2_InitialConfig (void)
{
    ret_code_t err_code;

    nrf_drv_gpiote_in_uninit(EXTSW2_CONTROL);

    if(!nrf_drv_gpiote_is_init())
    {
      err_code = nrf_drv_gpiote_init();
    }

    /**********Button6 i.e EXTSW2 pin Configuration Start *************************************************/
   //Set Button6 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t extsw2_in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    extsw2_in_config.pull = NRF_GPIO_PIN_PULLDOWN; //configure button pin as pull_down

    err_code = nrf_drv_gpiote_in_init(EXTSW2_CONTROL, &extsw2_in_config, extsw2_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(EXTSW2_CONTROL, true);
    /**********Button6 i.e EXTSW2 pin Configuration End *************************************************/
}

static void ExternalSwitch2_ConfigUpdate (void)
{
    ret_code_t err_code;
   
    nrf_drv_gpiote_in_uninit(EXTSW2_CONTROL);

    if(!nrf_drv_gpiote_is_init())
    {
      err_code = nrf_drv_gpiote_init();
    }

    /**********Button6 i.e EXTSW2 pin Configuration for both edge Start *************************************************/
   //Set Button6 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t extsw2_in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
    extsw2_in_config.pull = NRF_GPIO_PIN_PULLDOWN; //configure button pin as pull_down

    err_code = nrf_drv_gpiote_in_init(EXTSW2_CONTROL, &extsw2_in_config, extsw2_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(EXTSW2_CONTROL, true);
    /**********Button6 i.e EXTSW2 pin Configuration End *************************************************/

}
/*****************************************End***********************************************************/

static void doSelectionAndSaveMode (void)
{     
      ret_code_t     rc;

     switch(ExternalSwitchOpCase)
     {
     
        case CASE_NONE:
        break;

        case CASE_1:
        rc = nrf_fstorage_erase(&fstorage,FLASH_START_ADDRESS,1, NULL);
        APP_ERROR_CHECK(rc);
        //Set the External switches to the respective Operational Mode.
        for( ui8blink=0; ui8blink <=2; ui8blink++)
        {
          bsp_board_led_off(GREEN_LED);  //blink GREEN led while saving push button operation selected
          nrf_delay_ms(200);
          bsp_board_led_on(GREEN_LED);
          nrf_delay_ms(200);
        }
        rc = nrf_fstorage_write(&fstorage,FLASH_START_ADDRESS, &ui32SaveDataFlash, sizeof(ui32SaveDataFlash), NULL);
        APP_ERROR_CHECK(rc);
        break;

        case CASE_2:
        rc = nrf_fstorage_erase(&fstorage,FLASH_START_ADDRESS,1, NULL);
        APP_ERROR_CHECK(rc);
        //Set the External switches to the respective Operational Mode.
        for( ui8blink=0; ui8blink <=2; ui8blink++) //blink Red led while saving
        {
          bsp_board_led_off(RED_LED);  //blink RED led while saving normal 2way switch operation selected
          nrf_delay_ms(200);
          bsp_board_led_on(RED_LED);
          nrf_delay_ms(200);
        }
        rc = nrf_fstorage_write(&fstorage,FLASH_START_ADDRESS, &ui32SaveDataFlash, sizeof(ui32SaveDataFlash), NULL);
        APP_ERROR_CHECK(rc);
        break;

        case CASE_3:
        rc = nrf_fstorage_erase(&fstorage,FLASH_START_ADDRESS,1, NULL);
        APP_ERROR_CHECK(rc);
        //Set the External switches to the respective Operational Mode.
        for( ui8blink=0; ui8blink <=2; ui8blink++)
        {
          bsp_board_led_off(GREEN_LED);  //blink both leds while saving relay button operation selected
          bsp_board_led_off(RED_LED);
          nrf_delay_ms(200);
          bsp_board_led_on(GREEN_LED);
          bsp_board_led_on(RED_LED);
          nrf_delay_ms(200);
        }
        rc = nrf_fstorage_write(&fstorage,FLASH_START_ADDRESS, &ui32SaveDataFlash, sizeof(ui32SaveDataFlash), NULL);
        APP_ERROR_CHECK(rc);
         //Off the Dimmer
         on_off_set_value(0U);                    
         ui32DimmerONTime = 0;        
        break;

        default:
        break;
     }

}

static void LEDandCaseStatus (void)
{
     switch(ExternalSwitchOpCase)
     {
        case CASE_NONE:
        break;

        case CASE_1:
        bsp_board_led_off(GREEN_LED); //after 3sec turn ON GREEN_LED
        nrf_delay_ms(3000);   
        bsp_board_led_on(GREEN_LED); //power on process turn OFF GREEN_LED
        break;

        case CASE_2:
        bsp_board_led_off(RED_LED); //after 3sec turn ON RED_LED
        nrf_delay_ms(3000);   
        bsp_board_led_on(RED_LED); //power on process turn OFF RED_LED
        break;

        case CASE_3:
        bsp_board_led_off(RED_LED); //after 3sec turn ON RED_LED
        bsp_board_led_off(GREEN_LED); //after 3sec turn ON GREEN_LED
        nrf_delay_ms(3000);   
        bsp_board_led_on(RED_LED); //power on process turn OFF RED_LED
        bsp_board_led_on(GREEN_LED); //power on process turn OFF GREEN_LED
        break;

        default:
        break;
     }
  
}
/***************************Button4 pin handler functions Start*********************************************/
void optional1_key_in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{    
      nrf_delay_ms(100);
      nrf_drv_gpiote_in_event_enable(OPTIONAL2_KEY, true); //enable Optional2_key when Optional1_key press
      boolOperationCaseSelection = !boolOperationCaseSelection;
      
      //If flag is false then Save the selected case 
      if(!boolOperationCaseSelection)
      {
        doSelectionAndSaveMode();
        //Algorithm to save the selected operational case for External switches
        
        //Disable Optional Key 2
        nrf_drv_gpiote_in_event_disable(OPTIONAL2_KEY);  //disable Optional2_key interrupt
      }
      else
      {
        LEDandCaseStatus();   //LED and Previous Case status

        //Start external switch operational case selection
        ui8OptionalKey2Counter = 0;

      }
}     
/***************************Button4 pin handler functions End*********************************************/

/***************************Button5 pin handler functions Start*********************************************/
void optional2_key_in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{      
      nrf_delay_ms(100);  
          
      if(boolOperationCaseSelection)
      {
        ui8OptionalKey2Counter++;
        if(ui8OptionalKey2Counter >= MAX_CASE)
        {
            ui8OptionalKey2Counter = CASE_1;
        }

        switch(ui8OptionalKey2Counter)
        {
          case CASE_NONE:
          break;

          case CASE_1:
          //Set the External switches to the respective Operational Mode.
          bsp_board_led_off(GREEN_LED);    //Push button operation Green LED On
          bsp_board_led_on(RED_LED);   //other LED should Off
          ExternalSwitch2_InitialConfig();
          bool2WayButtonConfig = false;
          boolRelayOperation = false;
          ExternalSwitchOpCase = CASE_1;
          ui32SaveDataFlash = ExternalSwitchOpCase;
          break;

          case CASE_2:
          //Set the External switches to the respective Operational Mode.
          bsp_board_led_off(RED_LED);     //Normal 2way switch operation Red LED On
          bsp_board_led_on(GREEN_LED);    //other LED should Off
          ExternalSwitch2_InitialConfig();
          bool2WayButtonConfig = true;
          boolRelayOperation = false;
          ExternalSwitchOpCase = CASE_2;
          ui32SaveDataFlash = ExternalSwitchOpCase;
          break;

          case CASE_3:
          //Set the External switches to the respective Operational Mode.
          bsp_board_led_off(GREEN_LED);  //Relay Operation Both LED On
          bsp_board_led_off(RED_LED);  
          ExternalSwitch2_ConfigUpdate();  //when case 3 change ExtSw2 configurations to both edge detection
          boolRelayOperation = true;
          bool2WayButtonConfig = false;
          ExternalSwitchOpCase = CASE_3;
          ui32SaveDataFlash = ExternalSwitchOpCase;
          break;

          default:
          ui8OptionalKey2Counter = CASE_1;
          ExternalSwitchOpCase = CASE_1;
          ui32SaveDataFlash = ExternalSwitchOpCase;
          break;
        }
      }       
}     
/***************************Button5 pin handler functions End*********************************************/

/********** timer 1 Configuration Start *************************************************/
/**
* @brief Handler for timer events.
* 
* timer1_event_handler function to turn OFF the bulb and disable the timer 
*   
*/
void timer1_event_handler(nrf_timer_event_t event_type, void* p_context)
{   
      nrf_drv_timer_disable(&TIMER_1);        //disable timer 1
      
      //Negative cycle operation       
       if(ui32Brightness != 0) //User has turned off the light
       {
           if(ui32Brightness >= ui32DutyCycle100) //duty cycle is more than 9ms
           {
             timer2_DimmingControlling_tme(ui32DutyCycle100);  //timer 2 started for brightness control 
             nrf_gpio_pin_write(DIMMER_TRIGGER,1);     //when duty cycle is greater than 0 set trigger pin HIGH 
           }
           else
           {
             timer2_DimmingControlling_tme(ui32Brightness);  //timer 2 started for brightness control
             nrf_gpio_pin_write(DIMMER_TRIGGER,1);     //when duty cycle is greater than 0 set trigger pin HIGH
           }
       }
       if(ui32DimmerONTime == 0)
       {
          nrf_gpio_pin_write(DIMMER_TRIGGER,0);    //when duty cycle is 0 set trigger pin LOW
          ui32Brightness = 0;          
       }
       
       boolNextZCDProcess = true; //set this flag for next zcd detection 

        /***************Below statements are executed when ExtSw1 and ExtSw2 pressed*****************************************/
        //pushutton status check, 
        if(boolpushbuttonStatus)   //check push button ststus flag is set or not 
        {
           ui8Pushbuttonstatus = nrf_gpio_pin_read(EXTSW1_CONTROL);  // if the button flag is set then read the push button pin status 
           ui8ExtSW2Status = nrf_gpio_pin_read(EXTSW2_CONTROL);  // if the extsw2 flag is set then read the push button pin status 
           if((!bool2WayButtonConfig) && (!boolRelayOperation))
           {
               if(ui8Pushbuttonstatus == 1 || ui8ExtSW2Status == 1) //if the push button pin is high then enter to check button press count 
               {
                  ui8PushbuttonStatusCount+=4;    // increment the button press count 

                  if(ui8PushbuttonStatusCount > 50)  // if the button the press count is 100(1sec) then it is long press action 
                  {
                      /*function to brightness control
                      * on long press, increment and decrement the light intensity with the level of 10% 
                      */
                      if(boolBrightnesslevelcontrol)   // if the brightness level flag flase then start incrementing till maximun brightness 100%
                      {
                          if(m_dev_ctx.level_control_attr.current_level < 230)  
                          {
                              m_dev_ctx.level_control_attr.current_level = m_dev_ctx.level_control_attr.current_level + 13;                                                 
                          }
                          else 
                          {
                              m_dev_ctx.level_control_attr.current_level = 230;
                          }
                          level_control_set_value(m_dev_ctx.level_control_attr.current_level);
                      }
                      else
                      {
                          if(m_dev_ctx.level_control_attr.current_level >= 13)  
                          {
                              m_dev_ctx.level_control_attr.current_level = m_dev_ctx.level_control_attr.current_level - 13;                                                 
                          }
                          else 
                          {
                              m_dev_ctx.level_control_attr.current_level = 3;
                          }
                          level_control_set_value(m_dev_ctx.level_control_attr.current_level); 
                      }
                      ui8PushbuttonStatusCount = 0;
                      boolpushbuttonContinue = true;   
                  }
          
               }
               else if(ui8Pushbuttonstatus == 0 || ui8ExtSW2Status == 0)  // if the push button oinb status is not set the enter loop to toggle the light status 
               {
                  boolpushbuttonStatus = false;
                  if((ui8PushbuttonStatusCount >=15) && (ui8PushbuttonStatusCount <= 49) && (boolpushbuttonContinue == false))  // if the button press is single (between 400msec to 1sec) then toggle the light 
                  {
                      boolBrightnesslevelcontrol = !boolBrightnesslevelcontrol;
                      //function to toggle the LED current state
                      if(CurrentDutyCycle == 0)
                      {   
                          boolBrightnesslevelcontrol = false; //forcefully set the flag flase so next cycle of long press should be increment                      
                          level_control_set_value(m_dev_ctx.level_control_attr.current_level);
                          boolIgnorelongpress = false;
                      }
                      else
                      {                  
                         //Off the LED
                         on_off_set_value(0U);                    
                         ui32DimmerONTime = 0;
                         boolIgnorelongpress = true;                     
                      }
                  }
                  boolpushbuttonContinue = false; //set long press button flag false
                  ui8PushbuttonStatusCount = 0;   //button press count zero 
               }
           }

           //loop to check Relay Operation is On and Accept the input from ExtSw2
           if(boolRelayOperation)
           {
                //when ExtSw1 is detected
                if(ui8Pushbuttonstatus == 1) //if the push button pin is high then enter to check button press count 
                {
                  ui8PushbuttonStatusCount+=4;    // increment the button press count 

                  if(ui8PushbuttonStatusCount > 50)  // if the button the press count is 100(1sec) then it is long press action 
                  {
                      /*function to brightness control
                      * on long press, increment and decrement the light intensity with the level of 10% 
                      */
                      if(boolBrightnesslevelcontrol)   // if the brightness level flag flase then start incrementing till maximun brightness 100%
                      {
                          if(m_dev_ctx.level_control_attr.current_level < 230)  
                          {
                              m_dev_ctx.level_control_attr.current_level = m_dev_ctx.level_control_attr.current_level + 13;                                                 
                          }
                          else 
                          {
                              m_dev_ctx.level_control_attr.current_level = 230;
                          }
                          level_control_set_value(m_dev_ctx.level_control_attr.current_level);
                      }
                      else
                      {
                          if(m_dev_ctx.level_control_attr.current_level >= 13)  
                          {
                              m_dev_ctx.level_control_attr.current_level = m_dev_ctx.level_control_attr.current_level - 13;                                                 
                          }
                          else 
                          {
                              m_dev_ctx.level_control_attr.current_level = 3;
                          }
                          level_control_set_value(m_dev_ctx.level_control_attr.current_level); 
                      }
                      ui8PushbuttonStatusCount = 0;
                      boolpushbuttonContinue = true;   
                  }
          
                }
                else if(ui8Pushbuttonstatus == 0)  // if the push button oinb status is not set the enter loop to toggle the light status 
                {
                  boolpushbuttonStatus = false;
                  if(!boolIgnoreExtSw1OnOff)
                  {
                    if((ui8PushbuttonStatusCount >=15) && (ui8PushbuttonStatusCount <= 49) && (boolpushbuttonContinue == false))  // if the button press is single (between 400msec to 1sec) then toggle the light 
                    {
                        boolBrightnesslevelcontrol = !boolBrightnesslevelcontrol;
                        //function to toggle the LED current state
                        if(CurrentDutyCycle == 0)
                        {         
                            boolBrightnesslevelcontrol = false; //forcefully set the flag flase so next cycle of long press should be increment                        
                            level_control_set_value(m_dev_ctx.level_control_attr.current_level);
                            boolIgnorelongpress = false;   //Reset the flag to detect Up_key and Down_key long press
                            boolIgnoreExtSw2OnOff = true;  //while executing Case3 mode and Dimmer On from ExtSw1 input set this flag so that we can ignore ExtSw2 On/Off
                        }
                        else
                        {                  
                           //Off the LED
                           on_off_set_value(0U);                    
                           ui32DimmerONTime = 0;
                           boolIgnorelongpress = true;     //When Off then ignore Up_key and Down_key long press
                           boolIgnoreExtSw2OnOff = false;  //while executing Case3 mode and Dimmer Off then accept input from ExtSw2 and ExtSw1                  
                        }
                    }
                    boolpushbuttonContinue = false; //set long press button flag false
                    ui8PushbuttonStatusCount = 0;   //button press count zero 
                  }
                }
           }
    
        }
       /***************Above statements are executed when ExtSw1 and ExtSw2 pressed*****************************************/
        
        /***************Below statements are executed when button_2 pressed*****************************************/
        if(boolPushButton2Status)
        {
            ui8PushButton2status = nrf_gpio_pin_read(KEY_UP);
            if(ui8PushButton2status == 0)
            {   
               ui16PushButton2Count +=4; 
               if(!boolIgnorelongpress)  //ignore long press from up/down key when OFF 
               {
                  if(ui16PushButton2Count > 50)  //Increment brightness when button_2 long press
                  {
                      if(boolPushButton2BrightnessControl)
                      {
                        if(m_dev_ctx.level_control_attr.current_level < 230)  
                        {
                            m_dev_ctx.level_control_attr.current_level = m_dev_ctx.level_control_attr.current_level + 13;                                                 
                        }
                        else 
                        {
                            m_dev_ctx.level_control_attr.current_level = 230;
                        }
                        level_control_set_value(m_dev_ctx.level_control_attr.current_level);
    
                      }
                    ui16PushButton2Count = 0;
                    boolPushButton2Continue = true;
                  } 
               }
            }
            else if(ui8PushButton2status == 1)
            {
                boolPushButton2Status = false;
                boolPushButton2BrightnessControl = false;
                if(!boolIgnoreExtSw1OnOff)
                {
                    if((ui16PushButton2Count >=15) && (ui16PushButton2Count <= 49) && (boolPushButton2Continue == false))
                    {    
                         boolBrightnesslevelcontrol = false; //forcefully set the flag flase so next cycle of long press should be increment                                          
                         level_control_set_value(m_dev_ctx.level_control_attr.current_level); //Turn On when button_2 short press
                         boolIgnorelongpress = false;
                    }
                    ui16PushButton2Count = 0;
                    boolPushButton2Continue = false;
                }
            }
        }
        /***************Above statements are executed when button_2 pressed*****************************************/

        /***************Below statements are executed when button_3 pressed*****************************************/
        if(boolPushButton3Status)
        {
            ui8PushButton3status = nrf_gpio_pin_read(KEY_DOWN);
            if(ui8PushButton3status == 0)
            {
                ui16PushButton3Count +=4;
                if(!boolIgnorelongpress)    //ignore long press from up/down key when OFF 
                {                    
                    if(ui16PushButton3Count > 50)  //Decrement brightness when button_3 long press
                    {
                        if(boolPushButton3BrightnessControl)
                        {
                          if(m_dev_ctx.level_control_attr.current_level >= 13)  
                          {
                              m_dev_ctx.level_control_attr.current_level = m_dev_ctx.level_control_attr.current_level - 13;                                                 
                          }
                          else 
                          {
                              m_dev_ctx.level_control_attr.current_level = 3;
                          }
                          level_control_set_value(m_dev_ctx.level_control_attr.current_level); 

                        }
                      ui16PushButton3Count = 0;
                      boolPushButton3Continue = true;
                    }
                }
            }
            else if(ui8PushButton3status == 1)
            {
                boolPushButton3Status = false;
                boolPushButton3BrightnessControl = false;
                if(!boolIgnoreExtSw1OnOff)
                {
                    if((ui16PushButton3Count >=15) && (ui16PushButton3Count <= 49) && (boolPushButton3Continue == false))
                    {
                       //Turn Off when button_3 short press                                                         
                        ui32DimmerONTime = 0;
                        on_off_set_value(0U);
                        boolIgnorelongpress = true;
                    }
                    ui16PushButton3Count = 0;
                    boolPushButton3Continue = false;
                }
            }
        }
        /***************Above statements are executed when button_3 pressed*****************************************/
}

/**
* @brief function for timer1 configurarion
* 
* configure timer 1 with the frequency parameter set 1MHz
* Intialise the timer event handler and enable 10msec timer for Negative cycle  
*   
*/
void timer1_Configuration (void)
{  
    uint32_t err_code = NRF_SUCCESS;
    //Configure TIMER_1 as 10msec timer
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.frequency = 4; //set frequency 1MHz  
    err_code = nrf_drv_timer_init(&TIMER_1, &timer_cfg, timer1_event_handler);
    if (err_code != NRF_SUCCESS)
    {
        // handle error condition
    }
}

//fixed timer 1
void timer1_fixedtimeOperation (uint32_t ui32fixedtime)
{
  uint32_t time1_ticks;

  time1_ticks = nrf_drv_timer_us_to_ticks(&TIMER_1, ui32fixedtime); 
  nrf_drv_timer_extended_compare(
        &TIMER_1, NRF_TIMER_CC_CHANNEL0, time1_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);    //timer 1 configured as continous timer  
  nrf_drv_timer_clear(&TIMER_1);
  nrf_drv_timer_enable(&TIMER_1);
}
/**********Negative Cycle timer Configuration End *************************************************/


/**********************Duty Cycle timer Configuration Start ********************************************/
/**
* @brief Handler for timer events.
* 
* timer2_event_handler function to turn OFF the bulb and disable the timer 
*   
*/
void timer2_event_handler(nrf_timer_event_t event_type, void* p_context) //Timer 2 interrupt handler
{
     nrf_drv_timer_disable(&TIMER_2);    //disable timer 2
     nrf_gpio_pin_write(DIMMER_TRIGGER,0);  //set trigger pin LOW 
     if(boolNextZCDProcess)     //if negative cycle complete enable the ZCD event again for next interrupt
     {
       // enable ZCD event 
       nrf_drv_gpiote_in_event_enable(ZERO_CROSS_DETECTION,true);
       boolNextZCDProcess = false;
     }
     
}

/**
* @brief function for timer2 configurarion
* 
* configure timer 2 with the frequency parameter set 1MHz
* Intialise the timer event handler and enable 10msec to control the dimming effect 
*   
*/
void timer2_Configuration (void)
{  
    uint32_t err_code = NRF_SUCCESS;
    //Configure TIMER_2 as 0 to 10msec duty cycle timer
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.frequency = 4; //set frequency 1MHz  
    err_code = nrf_drv_timer_init(&TIMER_2, &timer_cfg, timer2_event_handler);
    if (err_code != NRF_SUCCESS)
    {
        // handle error condition
    }
}
//timer2 dimming control time function 
void timer2_DimmingControlling_tme(uint32_t ui32Timer2Dutycycle)
{
    time2_ticks = nrf_drv_timer_us_to_ticks(&TIMER_2, ui32Timer2Dutycycle); //ui32Timer2Dutycycle is passed as duty cycle value 0 to 100%

     nrf_drv_timer_extended_compare(
         &TIMER_2, NRF_TIMER_CC_CHANNEL0, time2_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);       //timer 2 configured as continous timer

    nrf_drv_timer_clear(&TIMER_2); 
    nrf_drv_timer_enable(&TIMER_2);
}
/**********************Duty Cycle timer Configuration End *************************************************/

/*************GPIO Configuration*******************************/
/* ************************************************************
*function to configure ZCD, Tigger and Button pin 
*  Configure ZCD as Digital input pin (P0_6)
*  Configure Trigger as Digital output pin (P0_8)
*  Configure Button as Digital input pin (P1_9)
*
*  Function : GPIO_pin_configuration(void);
***************************************************************/
static void GPIO_pin_configuration (void)
{
   uint32_t err_code;

     //Set ZCD pin as input pin and Configure ZCD handler
    if(!nrf_drv_gpiote_is_init())
    {
      err_code = nrf_drv_gpiote_init();
    }

    /**********Trigger pin Configuration Start *************************************************/
    //Set Trigger pin as output pin
     nrf_gpio_cfg_output(DIMMER_TRIGGER);
     /**********Trigger pin Configuration End *************************************************/
     
    /**********ZCD pin Configuration Start *************************************************/
    //Set ZCD pin as input pin and Configure ZCD handler
    nrf_drv_gpiote_in_config_t zcd_in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);   //raising edge detection
    zcd_in_config.pull = NRF_GPIO_PIN_PULLUP;   //configure ZCD pin as pull_up
    err_code = nrf_drv_gpiote_in_init(ZERO_CROSS_DETECTION, &zcd_in_config, zcd_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(ZERO_CROSS_DETECTION, true);
    /**********ZCD pin Configuration End *************************************************/

   /**********Button1 i.e EXTSW1 pin Configuration Start *************************************************/
   //Set Button1 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t button_in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    button_in_config.pull = NRF_GPIO_PIN_PULLDOWN; //configure button pin as pull_down

    err_code = nrf_drv_gpiote_in_init(EXTSW1_CONTROL, &button_in_config, button_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(EXTSW1_CONTROL, true);
    /**********Button1 i.e EXTSW1 pin Configuration End *************************************************/

    /**********Button6 i.e EXTSW2 pin Configuration Start *************************************************/
   //Set Button6 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t extsw2_in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    extsw2_in_config.pull = NRF_GPIO_PIN_PULLDOWN; //configure button pin as pull_down

    err_code = nrf_drv_gpiote_in_init(EXTSW2_CONTROL, &extsw2_in_config, extsw2_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(EXTSW2_CONTROL, true);
    /**********Button6 i.e EXTSW2 pin Configuration End *************************************************/

    /**********Button2 i.e KEY_UP pin Configuration Start *************************************************/
   //Set Button2 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t button2_in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    button2_in_config.pull = NRF_GPIO_PIN_PULLUP; //configure button pin as pull_up

    err_code = nrf_drv_gpiote_in_init(KEY_UP, &button2_in_config, button2_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(KEY_UP, true);
    /**********Button2 i.e KEY_UP pin Configuration End *************************************************/

   /**********Button3 i.e KEY_DOWN pin Configuration Start *************************************************/
   //Set Button3 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t button3_in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    button3_in_config.pull = NRF_GPIO_PIN_PULLUP; //configure button pin as pull_up

    err_code = nrf_drv_gpiote_in_init(KEY_DOWN, &button3_in_config, button3_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(KEY_DOWN, true);
    /**********Button3 i.e KEY_DOWN pin Configuration End *************************************************/

    /**********Button4 i.e Optional1 pin Configuration Start *************************************************/
   //Set Button3 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t optional1_key_in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    optional1_key_in_config.pull = NRF_GPIO_PIN_PULLUP; //configure button pin as pull_up

    err_code = nrf_drv_gpiote_in_init(OPTIONAL1_KEY, &optional1_key_in_config, optional1_key_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(OPTIONAL1_KEY, true);
    /**********Button4 i.e Optional1 pin Configuration End *************************************************/

   /**********Button5 i.e Optional2 pin Configuration Start *************************************************/
   //Set Button3 pin as input pin and Configure Button handler 
    nrf_drv_gpiote_in_config_t optional2_key_in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    optional2_key_in_config.pull = NRF_GPIO_PIN_PULLUP; //configure button pin as pull_up

    err_code = nrf_drv_gpiote_in_init(OPTIONAL2_KEY, &optional2_key_in_config, optional2_key_in_pin_handler);
    APP_ERROR_CHECK(err_code);

    /**********Button5 i.e Optional2 pin Configuration End *************************************************/

}

/**@brief Function for application main entry.
 */
int main(void)
{
    zb_ret_t       zb_err_code;
    zb_ieee_addr_t ieee_addr;
    ret_code_t     rc;
   
    /* Initialize timer, logging system and GPIOs. */
    log_init();
    leds_buttons_init();
    flash_initialization();   //flash init 

    GPIO_pin_configuration();   //GPIO initialization and configuration
    timer2_Configuration();     //Timer 2 as duty cycle time configured 
    timer1_Configuration();     //Timer 1 as negative cycle timer 
    adc_configure();            //ADC intialization and configuration as channal 2, 8 bit resolution
    

    /* 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("led_bulb");

    /* 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_router_role(IEEE_CHANNEL_MASK);
    zb_set_max_children(MAX_CHILDREN);
    zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
    zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));

    /* 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 dimmer switch device context (endpoints). */
    ZB_AF_REGISTER_DEVICE_CTX(&dimmable_light_ctx);

    bulb_clusters_attr_init();
    level_control_set_value(m_dev_ctx.level_control_attr.current_level);

    /** Start Zigbee Stack. */
    zb_err_code = zboss_start();
    ZB_ERROR_CHECK(zb_err_code);

    
//    bsp_board_led_off(GREEN_LED); //after 3sec turn ON GREEN_LED
//    nrf_delay_ms(3000);   
//    bsp_board_led_on(GREEN_LED); //power on process turn OFF GREEN_LED

 /*************************This below statement execute when power cycle is done and Read the data from flash**************************************/
    rc = nrf_fstorage_read(&fstorage,FLASH_START_ADDRESS,&ui32SaveDataFlash,sizeof(ui32SaveDataFlash));   //read count from flash
    APP_ERROR_CHECK(rc);
    if(ui32SaveDataFlash == 0xffffffff)
    {
        ui32SaveDataFlash = CASE_1;
        ExternalSwitchOpCase = CASE_1;
    }
    //when case 2 means normal 2way operation is set then Red LED blinks when data is read from flash
    else if(ui32SaveDataFlash == CASE_1)
    {
        ui32SaveDataFlash = CASE_1;
        ExternalSwitchOpCase = CASE_1;
        bool2WayButtonConfig = false;
        boolRelayOperation = false;
        for( ui8blink=0; ui8blink <=2; ui8blink++) //blink Red led while saving
        {
          bsp_board_led_off(GREEN_LED);  //blink RED led while saving normal 2way switch operation selected
          nrf_delay_ms(200);
          bsp_board_led_on(GREEN_LED);
          nrf_delay_ms(200);
        }
        
    }
    else if(ui32SaveDataFlash == CASE_2)//when case 1 means push button operation is set then Green LED blinks when data is read from flash
    {
        ui32SaveDataFlash = CASE_2;
        ExternalSwitchOpCase = CASE_2;
        bool2WayButtonConfig = true;
        boolRelayOperation = false;
        for( ui8blink=0; ui8blink <=2; ui8blink++) //blink Red led while saving
        {
          bsp_board_led_off(RED_LED);  //blink RED led while saving normal 2way switch operation selected
          nrf_delay_ms(200);
          bsp_board_led_on(RED_LED);
          nrf_delay_ms(200);
        }
       
    }
    else if(ui32SaveDataFlash == CASE_3)
    {
        ui32SaveDataFlash = CASE_3;
        ExternalSwitchOpCase = CASE_3;
        on_off_set_value(0U);                    
        ui32DimmerONTime = 0;  
        boolRelayOperation = true;
        bool2WayButtonConfig = false;
        ExternalSwitch2_ConfigUpdate();  //when case 3 change ExtSw2 configurations to both edge detection
        for( ui8blink=0; ui8blink <=2; ui8blink++)
        {
          bsp_board_led_off(GREEN_LED);  //blink both leds while saving relay button operation selected
          bsp_board_led_off(RED_LED);
          nrf_delay_ms(200);
          bsp_board_led_on(GREEN_LED);
          bsp_board_led_on(RED_LED);
          nrf_delay_ms(200);
        }
        
    }
    
/*************************This above statement execute when power cycle is done and Read the data from flash**************************************/
   
    while(1)
    {
        if(boolInitialSequenceMeasurement)
        {
            InitialSequence();  
        }
        zboss_main_loop_iteration();
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());

    }
}


/**
 * @}
 */
