This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Configure timer for 10msec as well as 5sec for Alexa bonding erase

Hi All,

I am developing a Zigbee based light controlling product using nrf52840 and nRF5_SDK_for_Thread_and_Zigbee_v3.0.0_d310e71 SDK.

All functionality and features developed and tested successfully. All are working without any problem.

Basic device functioning is,

1) Detect ZCD raising edge and start Timer1 for 10msec and Trigger GPIO pin high (LED) and with duty cycle Timer 2 (Positive AC cycle control)

2) Once the 10msec timer (Timer1) is over again trigger GPIO pin high(LED) with a duty cycle Timer 2 (Negative AC cycle control)

3) If duty cycle timer 2 is over Set trigger GPIO pin Low (LED)

4) Repeat all 3 steps to control lights using Alexa

- Till here all functions working perfectly.

One more measure function is in the development process that is erasing bonding information of Device and Alexa device.

My simple logic is to use a timer of 5sec and within 5sec if the device RESET is done for 3times then blink LED and erase bonding information. So to achieve this what I did is I am reenabling the 10msec timer for 5sec when bonding is in process and counting the reset cycle (if it is 3 time within 5sec timer then erase else make count 0 and continue normal functioning).

If I configure timer 1 for both 10msec and 5sec then it is not working. Either it is working for 10msec purely or 5sec purely. As 5sec not working my bonding erase logic not working.

Please find the below attached main file and let me what I did wrong in configuring the timer for the same.

/**
 * 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)
 */

/* Includes ------------------------------------------------------------------*/
#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"

//flash include files 
#include "nrf_fstorage.h"
#include "nrf_fstorage_nvmc.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 "drv_ws2812.h"
#include "nrf_delay.h"

#include "hardfault.h"
/* MACROS ---------------------------------------------------------*/

#define MAX_CHILDREN                      10                                    /**< The maximum amount of connected devices. Setting this value to 0 disables association to this device.  */              
#define IEEE_CHANNEL_MASK                  (ZB_TRANSCEIVER_ALL_CHANNELS_MASK)   /**< Scan all, predefined channel to find the coordinator. */
#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_2                       /**< LED indicating that light switch successfully joind ZigBee network. */
#endif

#define ZCD_IN_PIN                            NRF_GPIO_PIN_MAP(0,6)             /**< ZCD pin configuration, this is the input pin to read the interrupt*/

#ifndef ZCD_IN_PIN 
    #error "Please indicate input pin"
#endif

#define DIMMER_TRIGGER_OUT_PIN                NRF_GPIO_PIN_MAP(0,8)            /**< Dimmer trigger pin configuration, this is the output pin to drive the LED/BULB*/

#ifndef DIMMER_TRIGGER_OUT_PIN
    #error "Please indicate output pin"
#endif

//Flash related MACROS 
#define FLASH_START_ADDRESS           0x3F000
#define FLASH_END_ADDRESS             0x3FFFF

//Brightness level Macros
#define BRIGHTNESS_DUTYCYCLE_0					0
#define BRIGHTNESS_DUTYCYCLE_5					7.80
#define BRIGHTNESS_DUTYCYCLE_10					15.50
#define BRIGHTNESS_DUTYCYCLE_15					22.70
#define BRIGHTNESS_DUTYCYCLE_20					29.40

#define BRIGHTNESS_DUTYCYCLE_25					35.40
#define BRIGHTNESS_DUTYCYCLE_30					40.50
#define BRIGHTNESS_DUTYCYCLE_35					44.60
#define BRIGHTNESS_DUTYCYCLE_40					47.60
#define BRIGHTNESS_DUTYCYCLE_45					49.40

#define BRIGHTNESS_DUTYCYCLE_50					50.00
#define BRIGHTNESS_DUTYCYCLE_55					50.60
#define BRIGHTNESS_DUTYCYCLE_60					52.40
#define BRIGHTNESS_DUTYCYCLE_65					55.40
#define BRIGHTNESS_DUTYCYCLE_70					59.50

#define BRIGHTNESS_DUTYCYCLE_75					64.60
#define BRIGHTNESS_DUTYCYCLE_80					70.60
#define BRIGHTNESS_DUTYCYCLE_85					77.30
#define BRIGHTNESS_DUTYCYCLE_90					84.50
#define BRIGHTNESS_DUTYCYCLE_95					92.20
#define BRIGHTNESS_DUTYCYCLE_100				100

/* 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


/* Private variables ---------------------------------------------------------*/
//brigthness duty cycle array
float Light_DutyCycle[21] = {
                              BRIGHTNESS_DUTYCYCLE_0,
                              BRIGHTNESS_DUTYCYCLE_5,
                              BRIGHTNESS_DUTYCYCLE_10,
                              BRIGHTNESS_DUTYCYCLE_15,
                              BRIGHTNESS_DUTYCYCLE_20,

                              BRIGHTNESS_DUTYCYCLE_25,
                              BRIGHTNESS_DUTYCYCLE_30,
                              BRIGHTNESS_DUTYCYCLE_35,
                              BRIGHTNESS_DUTYCYCLE_40,
                              BRIGHTNESS_DUTYCYCLE_45,

                              BRIGHTNESS_DUTYCYCLE_50,
                              BRIGHTNESS_DUTYCYCLE_55,
                              BRIGHTNESS_DUTYCYCLE_60,
                              BRIGHTNESS_DUTYCYCLE_65,
                              BRIGHTNESS_DUTYCYCLE_70,

                              BRIGHTNESS_DUTYCYCLE_75,
                              BRIGHTNESS_DUTYCYCLE_80,
                              BRIGHTNESS_DUTYCYCLE_85,
                              BRIGHTNESS_DUTYCYCLE_90,
                              BRIGHTNESS_DUTYCYCLE_95,
                              BRIGHTNESS_DUTYCYCLE_100
                            };

uint8_t ui8ModResult = 0;

uint32_t time_us = 0;
uint32_t time_ticks;
uint32_t ui32DimmerONTime = 0,ui32CurrentBrightness = 0;
uint32_t ui32LastBrightness = 10000;				// Value of last brightness between 0 to 64
uint32_t ui32ZCDCounts = 0;

/*************BOOLEAN VARIABLES******************************/
bool boolDimmerTrigger = false;
bool boolZCDTrigger = false;
bool boolSetBondingErase = false;  //Rohit Testing
bool boolEraseFlash = false;
/* These variables are used for read, write operation in flash.
   Because the fstorage interface is asynchrounous, the data must be kept in memory.
 */
uint32_t ui8ResetReadCount = 0;
uint32_t ui8ResetWriteCount = 0;
ret_code_t     rc;

/* External variables ---------------------------------------------------------*/


/* Private function prototypes -----------------------------------------------*/

const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(4);          //timer 4 instance creation and declaration  
const nrf_drv_timer_t TIMER2_RESET = NRF_DRV_TIMER_INSTANCE(2);       //timer 2 instance creation and declaration 

/* Functions definitions -----------------------------------------------------*/
//timer 4 creation function 
void timer4_Configuration(void);
void timer4_OperatingTime(void);

                                         
//timer 2 creation function
void timer2_Configuration(void);
void start_5secResetCalculateTimer(void);              //timer to erase bonding infromation 
void start_10msecTimer(void);                          //timer to dimming operation for negative cycle 


/* 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;


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 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;
    }
}

/**@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 Sets brightness of on-board 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)
{
     /* Scale level value: timer uses 0-100 scale, but ZigBee level control cluster uses values from 0 up to 255. */
      ui32CurrentBrightness = ((brightness_level * 100)/ 255);
      ui8ModResult = ui32CurrentBrightness % 5; //take mode 5 of brightness level 
      if( ui8ModResult != 0)
      {
            if(ui8ModResult <= 2)   //if brightness level mode is not 0 then check, if it is less than or equal to 2 
                  ui32DimmerONTime = ui32CurrentBrightness - ui8ModResult;    // if Yes, then map the brightness level to nearest round value
            else
                  ui32DimmerONTime = (5 - ui8ModResult)+ ui32CurrentBrightness;  //if the brightness level mode is greater than 2, then map brightness level to next nearest round value
      }
      else
      {
          ui32DimmerONTime = ui32CurrentBrightness;	  //if mode of 5 is zero then operate brightness level to given user brightness level
      }
      ui8ModResult = ui32DimmerONTime / 5;     
      //set brightness level their respective index luminas value.  
      ui32LastBrightness = Light_DutyCycle[ui8ModResult]* 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);
    }
    else
    {
        light_bulb_set_brightness(0U);
      
    }
}



/**@brief Function for initializing LEDs and a single PWM channel.
 */
static void leds_buttons_init(void)
{

      bsp_board_init(BSP_INIT_LEDS);    // Initialization the board leds 
 
}

/**
* @brief Handler for ZCD events.
* 
* ZCD_handler function to read the input pin P0_6 interrupt at every 10ms
* Incorporated the dimming effect dependance upon the time values  
* Start timer 4 and timer 0   
*/
void ZCD_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{ 
    if(!boolZCDTrigger)
    {
         //read the ZCD pulse if the count is 1 then goto next operation step
        if(++ui32ZCDCounts ==1)
        {
             
              start_10msecTimer();       // start 10msec timer for ZCD adjustment and operate Dimming of LED
               //increment the dimmer brightness in steps 0.3% to soft start and stop 
              if(time_us < ui32LastBrightness)
              {
                  time_us += 20;	 	
                  if(time_us >= 9960)
                  {
                      time_us = 10000;
                  }                                   
              }
              //decrease the dimmer brightness in steps 0.3% to soft start and stop 
              if(time_us > ui32LastBrightness)
              {
                  time_us -= 20;	 	
                  if(time_us <= 20)
                  { 
                      time_us = 0;
                  }
          
              }
              //if the time 10ms and birghtness level is 100% then turn ON the LED/BULB 
              if(ui32LastBrightness == 10000 && time_us == 10000)
              {
                nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN, 1);   // turn ON the LED/BULB
              }
              //if the time is 0ms and brightness level is 0% then turn OFF the LED/BULB
              else if(ui32LastBrightness == 0 && time_us == 0)
              {
                nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN, 0);   // turn OFF the LED/BULB 
              }
              else
              {
                nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN, 1);
                boolDimmerTrigger = true;
                timer4_OperatingTime();   // start the timer4 
              }

              ui32ZCDCounts = 0;

        }
    }
              
}

/**
* @brief Handler for timer events.
* 
* timer_led_event_handler function to turn OFF the bulb and disable the timer 
*   
*/
void timer_led_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    if(boolDimmerTrigger)
    {
      // turn Off the dimer
      nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN, 0);
 
      boolDimmerTrigger = false;
    }
    nrf_drv_timer_disable(&TIMER_LED);   //disable the timer 

}
  
/**
* @brief function for timer4 initialization.
* 
* timer4creates_start function to configure timer 4 with the frequency parameter set 1MHz
* Intialise the timer event handler and start the timer in us to control the dimming effect 
*   
*/
//Intialize the timer 4
//Configure the timer 4 for set the brightness value interms of time
void timer4_Configuration(void)
{
    uint32_t err_code = NRF_SUCCESS;

    //Configure TIMER_LED for generate brightness controll of LED
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.frequency = 4;
    err_code = nrf_drv_timer_init(&TIMER_LED, &timer_cfg, timer_led_event_handler);
    if (err_code != NRF_SUCCESS)
    {
        // handle error condition
    }

}

void timer4_OperatingTime(void)
{
    time_ticks = nrf_drv_timer_us_to_ticks(&TIMER_LED, time_us);

    nrf_drv_timer_extended_compare(
         &TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);


    nrf_drv_timer_enable(&TIMER_LED);
}


/**
* @brief function for timer 2 interrupt handler timer2_reset_handler
* 
*This handler is used for operate negative cycle dimming and erase the flash reset read and write count value  
* and disable the timer
*/ 
void timer2_reset_handler(nrf_timer_event_t event_type, void* p_context)
{
        nrf_drv_timer_disable(&TIMER2_RESET);   //disable the timer
        //increment the dimmer brightness in steps 0.5% to soft start and stop 
        if(time_us < ui32LastBrightness)
        {
            time_us += 20;	 	
            if(time_us >= 9960)
            {
                time_us = 10000;
            }                                   
        }
        //decrease the dimmer brightness in steps 0.5% to soft start and stop 
        if(time_us > ui32LastBrightness)
        {
            time_us -= 20;	 	
            if(time_us <= 20)
            { 
                time_us = 0;
            }
            
        }
       //if the time 10ms and birghtness level is 100% then turn ON the LED/BULB 
        if(ui32LastBrightness == 10000 && time_us == 10000)
        {
          nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN, 1);   // turn ON the LED/BULB
        }
        //if the time is 0ms and brightness level is 0% then turn OFF the LED/BULB
        else if(ui32LastBrightness == 0 && time_us == 0)
        {
          nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN, 0);   // turn OFF the LED/BULB 
        }
        else
        {
          nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN, 1);
          boolDimmerTrigger = true;
          timer4_OperatingTime();   // start the timer4 
        }

      
      //check the erase flasg set, if the reset cycle count is less than 3 then enter loop to erase the read/write count from flash after 5sec timer elapsed 
      if(boolEraseFlash)
      {
        ui8ResetWriteCount = 0;
        ui8ResetReadCount = 0;
        rc = nrf_fstorage_erase(&fstorage,FLASH_START_ADDRESS,1, NULL);
        APP_ERROR_CHECK(rc);
        boolZCDTrigger = false;
        boolSetBondingErase = false;
        boolEraseFlash = false;
        nrf_drv_timer_disable(&TIMER2_RESET);   //disable the timer 
       // start_10msecTimer();//after 5sec timer elapsed again start the 10msec timer
        
      } 

}

/**
* @brief function for timer 2 initialization.
* 
* timer2creates_start function to configure timer 2 for 5sec 
* 
*/
//Intialize the timer 2
//Configure the timer 0 for 5sec time to calculate 3x reset to erase bonding information
void timer2_Configuration(void)
{
    uint32_t err_code = NRF_SUCCESS;

   //Configure TIMER2_RESET for generating 5sec Reset calculate timer.
    nrf_drv_timer_config_t timer_cfg;
    timer_cfg.frequency = 4;     //1MHz frequecy
    timer_cfg.bit_width = 3;     //32 bit width
    timer_cfg.mode = 0;

    err_code = nrf_drv_timer_init(&TIMER2_RESET, &timer_cfg, timer2_reset_handler);
    if (err_code != NRF_SUCCESS)
    {
        // handle error condition
    }
}

//5sec timer configuration 
void start_5secResetCalculateTimer(void)
{
    uint32_t time2_ms = 5000;
    uint32_t time2_ticks;
	
    time2_ticks = nrf_drv_timer_ms_to_ticks(&TIMER2_RESET, time2_ms);

    nrf_drv_timer_extended_compare(
         &TIMER2_RESET, NRF_TIMER_CC_CHANNEL0, time2_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    nrf_drv_timer_enable(&TIMER2_RESET);
}

//10msec timer configuration 
void start_10msecTimer(void)
{
    uint32_t time2_ms = 10000;
    uint32_t time2_ticks;
	
    time2_ticks = nrf_drv_timer_us_to_ticks(&TIMER2_RESET, time2_ms);

    nrf_drv_timer_extended_compare(
         &TIMER2_RESET, NRF_TIMER_CC_CHANNEL0, time2_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    nrf_drv_timer_enable(&TIMER2_RESET);
}

/**
 * @brief Function for configuring: ZCD_IN_PIN pin for input,
 * and configures GPIOTE to give an interrupt on pin change.
 */
static void gpio_init(void)
{
    uint32_t err_code;
	
    if(!nrf_drv_gpiote_is_init())
    {
      err_code = nrf_drv_gpiote_init();
    }

    //Configure the Dimmer output pin trigger pin 
    nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_TASK_HIGH;
    //GPIOTE_CONFIG_OUT_SIMPLE(false);
    
    err_code = nrf_drv_gpiote_out_init(DIMMER_TRIGGER_OUT_PIN, &out_config);
    if (err_code != NRF_SUCCESS)
    {
        // handle error condition
    }

    //Configure the ZCD input pin 
    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); //GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
    in_config.pull = NRF_GPIO_PIN_PULLUP; //NRF_GPIO_PIN_PULLUP;
    err_code = nrf_drv_gpiote_in_init(ZCD_IN_PIN, &in_config, ZCD_handler);
    if (err_code != NRF_SUCCESS)
    {
        // handle error condition
    }

    //Enable the interrupt the pin event handler
    nrf_drv_gpiote_in_event_enable(ZCD_IN_PIN, true);

}

/**@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);
    }
}

//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);
}
/**@brief Function for application main entry. 
 */
int main(void)
{
    zb_ret_t       zb_err_code;
    zb_ieee_addr_t ieee_addr;

    /* Initialize timer, logging system and GPIOs. */

    log_init();
    leds_buttons_init();
    gpio_init();
    timer4_Configuration();
    timer2_Configuration();    //start timer to count device power On/Off cycle
    flash_initialization();   //flash init 

    /* 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);
   
    rc = nrf_fstorage_read(&fstorage,FLASH_START_ADDRESS,&ui8ResetReadCount,sizeof(ui8ResetReadCount));   //read count from flash
    APP_ERROR_CHECK(rc);

    if(ui8ResetReadCount == 0xFFFFFFFF)   //if the read data is 0xffffff then map ui8ResetReadCount to zero
          ui8ResetReadCount = 1;
    //check the device turn On/Off cycle is 3. if yes, then erase the device boanding information and reset the device 
    if((ui8ResetReadCount % 3)==0)   
    {
        
        boolZCDTrigger = true;

        nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN,1);
        nrf_delay_ms(500);
        nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN,0);
        nrf_delay_ms(500);
        nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN,1);
        nrf_delay_ms(500);
        nrf_gpio_pin_write(DIMMER_TRIGGER_OUT_PIN,0);
        nrf_delay_ms(500);      
       
        rc = nrf_fstorage_erase(&fstorage,FLASH_START_ADDRESS,1, NULL);
        APP_ERROR_CHECK(rc);
        ui8ResetWriteCount = 0;
        ui8ResetReadCount = 0;
        
        zigbee_erase_persistent_storage(ZB_TRUE);
        boolZCDTrigger = false;

        //start_10msecTimer();//after the bonding info erased again start the 10msec timer
    }
    else
    {
        //if the device ON/Off cycle is less than 3, continue with device normal operation and ui8ResetWriteCount to flash with increment by 1. 
        rc = nrf_fstorage_erase(&fstorage,FLASH_START_ADDRESS,1, NULL);
        APP_ERROR_CHECK(rc);

        ui8ResetWriteCount = ui8ResetReadCount+1;
        rc = nrf_fstorage_write(&fstorage,FLASH_START_ADDRESS, &ui8ResetWriteCount, sizeof(ui8ResetWriteCount), NULL);
        APP_ERROR_CHECK(rc);
        boolSetBondingErase = true;  //start timer to count device power On/Off cycle
    }

    if(boolSetBondingErase)
    {
       start_5secResetCalculateTimer();
       boolEraseFlash = true;
    }

    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);



    while(1)
    {
        zboss_main_loop_iteration();
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());

    }
}


/**
 * @}
 */

Note - timer naming is post is a logical explanation.

Thanks in advance

Regards

Rohit R

Related