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