hi,
i am trying to on/off led on board(light_bulb code) which is controlled by the other board(light_switch code) with a gpio. when gpio is high led should be on and when it is low led should be off.
please check my code. i am facing problem.
/**
* 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 "zboss_api_addons.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 "drv_ws2812.h"
#include "nrf_802154.h"
#define MAX_CHILDREN 10 /**< The maximum amount of connected devices. Setting this value to 0 disables association to this device. */
#define IEEE_CHANNEL_MASK (1l << ZIGBEE_CHANNEL) /**< Scan only one, 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. */
#define BULB_PWM_NAME PWM1 /**< PWM instance used to drive dimmable light bulb. */
#define BULB_PWM_TIMER 2 /**< Timer number used by PWM. */
/* 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. */
#ifdef BOARD_PCA10059 /**< If it is Dongle */
#define IDENTIFY_MODE_BSP_EVT BSP_EVENT_KEY_0 /**< Button event used to enter the Bulb into the Identify mode. */
#define ZIGBEE_NETWORK_STATE_LED BSP_BOARD_LED_0 /**< LED indicating that light switch successfully joind ZigBee network. */
#else
#define IDENTIFY_MODE_BSP_EVT BSP_EVENT_KEY_3 /**< Button event used to enter the Bulb into the Identify mode. */
#define ZIGBEE_NETWORK_STATE_LED BSP_BOARD_LED_2 /**< LED indicating that light switch successfully joind ZigBee network. */
#endif
#define BULB_LED BSP_BOARD_LED_3 /**< LED immitaing dimmable light bulb. */
#if (APP_BULB_USE_WS2812_LED_CHAIN)
#define LED_CHAIN_DOUT_PIN NRF_GPIO_PIN_MAP(1,7) /**< GPIO pin used as DOUT (to be connected to DIN pin of the first ws2812 led in chain) */
#endif
#define PAIR_LED NRF_GPIO_PIN_MAP(0,29)
#define BULB NRF_GPIO_PIN_MAP(0,13)
#define TX_POWER_LEVEL 12
/* 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
/* Main application customizable context. Stores all settings and static values. */
typedef struct
{
zb_zcl_basic_attrs_ext_t basic_attr;
zb_zcl_identify_attrs_t identify_attr;
zb_zcl_scenes_attrs_t scenes_attr;
zb_zcl_groups_attrs_t groups_attr;
zb_zcl_on_off_attrs_ext_t on_off_attr;
zb_zcl_level_control_attrs_t level_control_attr;
} bulb_device_ctx_t;
APP_PWM_INSTANCE(BULB_PWM_NAME, BULB_PWM_TIMER);
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);
#if (APP_BULB_USE_WS2812_LED_CHAIN)
/**@brief Timer responsible for triggering periodic led chain refresh */
APP_TIMER_DEF(m_ws2812_refresh_timer);
/** @brief Requests a led chain refresh */
static volatile bool m_ws2812_refresh_request;
#endif
/**@brief Function for initializing the application timer.
*/
static void timer_init(void)
{
uint32_t error_code = app_timer_init();
APP_ERROR_CHECK(error_code);
}
/**@brief Function for initializing the nrf log module.
*/
static void log_init(void)
{
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}
/**@brief 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)
{
app_pwm_duty_t app_pwm_duty;
/* Scale level value: APP_PWM uses 0-100 scale, but ZigBee level control cluster uses values from 0 up to 255. */
app_pwm_duty = (brightness_level * 100U) / 255U;
/* Set the duty cycle - keep trying until PWM is ready. */
while (app_pwm_channel_duty_set(&BULB_PWM_NAME, 0, app_pwm_duty) == NRF_ERROR_BUSY)
{
}
}
#if (APP_BULB_USE_WS2812_LED_CHAIN)
/**@brief Sets brightness of ws2812 led chain
*
* @param[in] brightness_level Brightness level, allowed values 0 ... 255, 0 - turn off, 255 - full brightness
*/
static void light_bulb_ws2812_chain_set_brightness(zb_uint8_t brightness_level)
{
uint32_t color;
/* Decrease brightness just to save your eyes. LEDs can be very bright */
if (brightness_level >= 2U)
{
brightness_level /= 2U;
}
color = ((uint32_t)brightness_level << 16); /* Red component */
color |= ((uint32_t)brightness_level << 8); /* Green component */
color |= (uint32_t)brightness_level; /* Blue component */
drv_ws2812_set_pixel_all(color);
/* Main loop will take care of refreshing led chain */
m_ws2812_refresh_request = true;
}
#endif
/**@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);
#if (APP_BULB_USE_WS2812_LED_CHAIN)
light_bulb_ws2812_chain_set_brightness(brightness_level);
#endif
}
/**@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);
nrf_gpio_pin_set(BULB);
}
else
{
light_bulb_set_brightness(0U);
nrf_gpio_pin_clear(BULB);
}
}
/**@brief Callback for button events.
*
* @param[in] evt Incoming event from the BSP subsystem.
*/
static void buttons_handler(bsp_event_t evt)
{
zb_ret_t zb_err_code;
switch(evt)
{
case IDENTIFY_MODE_BSP_EVT:
/* Check if endpoint is in identifying mode, if not put desired endpoint in identifying mode. */
if (m_dev_ctx.identify_attr.identify_time == ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE)
{
NRF_LOG_INFO("Bulb put in identifying mode");
zb_err_code = zb_bdb_finding_binding_target(HA_DIMMABLE_LIGHT_ENDPOINT);
ZB_ERROR_CHECK(zb_err_code);
}
else
{
NRF_LOG_INFO("Cancel F&B target procedure");
zb_bdb_finding_binding_target_cancel();
}
break;
default:
NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
break;
}
}
/**@brief Function for initializing LEDs and a single PWM channel.
*/
static void leds_buttons_init(void)
{
ret_code_t err_code;
app_pwm_config_t pwm_cfg = APP_PWM_DEFAULT_CONFIG_1CH(5000L, bsp_board_led_idx_to_pin(BULB_LED));
/* Initialize all LEDs and buttons. */
err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
APP_ERROR_CHECK(err_code);
/* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
/* Initialize PWM running on timer 1 in order to control dimmable light bulb. */
err_code = app_pwm_init(&BULB_PWM_NAME, &pwm_cfg, NULL);
APP_ERROR_CHECK(err_code);
app_pwm_enable(&BULB_PWM_NAME);
while (app_pwm_channel_duty_set(&BULB_PWM_NAME, 0, 99) == NRF_ERROR_BUSY)
{
}
}
/**@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);
nrf_gpio_pin_set(PAIR_LED);
}
else
{
NRF_LOG_ERROR("Failed to join network. Status: %d", status);
bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
nrf_gpio_pin_clear(PAIR_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);
nrf_gpio_pin_clear(PAIR_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);
}
}
#if (APP_BULB_USE_WS2812_LED_CHAIN)
static void ws2812_refresh_timer_timeout_handler(void *p_context)
{
m_ws2812_refresh_request = true;
}
#endif
/**@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. */
timer_init();
log_init();
leds_buttons_init();
#if (APP_BULB_USE_WS2812_LED_CHAIN)
ret_code_t ret_code;
ret_code = drv_ws2812_init(LED_CHAIN_DOUT_PIN);
APP_ERROR_CHECK(ret_code);
#endif
/* 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);
#if (APP_BULB_USE_WS2812_LED_CHAIN)
/* Let's have a timer triggering refresh of led state */
ret_code = app_timer_create(&m_ws2812_refresh_timer, APP_TIMER_MODE_REPEATED,
ws2812_refresh_timer_timeout_handler);
APP_ERROR_CHECK(ret_code);
ret_code = app_timer_start(m_ws2812_refresh_timer, APP_TIMER_TICKS(5000U), NULL);
APP_ERROR_CHECK(ret_code);
#endif
/** Start Zigbee Stack. */
zb_err_code = zboss_start();
ZB_ERROR_CHECK(zb_err_code);
nrf_802154_tx_power_set(TX_POWER_LEVEL);
nrf_gpio_cfg_output(PAIR_LED);
nrf_gpio_cfg_output(BULB);
while(1)
{
zboss_main_loop_iteration();
UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
#if (APP_BULB_USE_WS2812_LED_CHAIN)
if (m_ws2812_refresh_request)
{
if (drv_ws2812_display(NULL, NULL) == NRF_SUCCESS)
{
m_ws2812_refresh_request = false;
}
}
#endif
}
}
/**
* @}
*/
light_bulb.c
/**
* 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_switch main.c
* @{
* @ingroup zigbee_examples
* @brief Dimmer switch for HA profile implementation.
*/
#include "zboss_api.h"
#include "zb_mem_config_min.h"
#include "zb_error_handler.h"
#include "zigbee_helpers.h"
#include "app_timer.h"
#include "bsp.h"
#include "boards.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_802154.h"
#define IEEE_CHANNEL_MASK (1l << ZIGBEE_CHANNEL) /**< Scan only one, predefined channel to find the coordinator. */
#define LIGHT_SWITCH_ENDPOINT 1 /**< Source endpoint used to control light bulb. */
#define MATCH_DESC_REQ_START_DELAY (2 * ZB_TIME_ONE_SECOND) /**< Delay between the light switch startup and light bulb finding procedure. */
#define MATCH_DESC_REQ_TIMEOUT (5 * ZB_TIME_ONE_SECOND) /**< Timeout for finding procedure. */
#define MATCH_DESC_REQ_ROLE ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE /**< Find only non-sleepy device. */
#define ERASE_PERSISTENT_CONFIG ZB_FALSE /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. NOTE: If this option is set to ZB_TRUE then do full device erase for all network devices before running other samples. */
#define ZIGBEE_NETWORK_STATE_LED BSP_BOARD_LED_2 /**< LED indicating that light switch successfully joind ZigBee network. */
#define BULB_FOUND_LED BSP_BOARD_LED_3 /**< LED indicating that light witch found a light bulb to control. */
#define LIGHT_SWITCH_BUTTON_ON BSP_BOARD_BUTTON_0 /**< Button ID used to switch on the light bulb. */
#define LIGHT_SWITCH_BUTTON_OFF BSP_BOARD_BUTTON_1 /**< Button ID used to switch off the light bulb. */
#define SLEEPY_ON_BUTTON BSP_BOARD_BUTTON_2 /**< Button ID used to determine if we need the sleepy device behaviour (pressed means yes). */
#define LIGHT_SWITCH_DIMM_STEP 15 /**< Dim step size - increases/decreses current level (range 0x000 - 0xfe). */
#define LIGHT_SWITCH_DIMM_TRANSACTION_TIME 2 /**< Transition time for a single step operation in 0.1 sec units. 0xFFFF - immediate change. */
#define LIGHT_SWITCH_BUTTON_THRESHOLD ZB_TIME_ONE_SECOND /**< Number of beacon intervals the button should be pressed to dimm the light bulb. */
#define LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO ZB_MILLISECONDS_TO_BEACON_INTERVAL(50) /**< Delay between button state checks used in order to detect button long press. */
#define LIGHT_SWITCH_BUTTON_LONG_POLL_TMO ZB_MILLISECONDS_TO_BEACON_INTERVAL(300) /**< Time after which the button state is checked again to detect button hold - the dimm command is sent again. */
#if !defined ZB_ED_ROLE
#error Define ZB_ED_ROLE to compile light switch (End Device) source code.
#endif
#define PAIR_LED NRF_GPIO_PIN_MAP(1,11)
#define IN1 NRF_GPIO_PIN_MAP(1,10)
#define BULB NRF_GPIO_PIN_MAP(0,27)
#define TX_POWER_LEVEL 12
typedef struct light_switch_bulb_params_s
{
zb_uint8_t endpoint;
zb_uint16_t short_addr;
} light_switch_bulb_params_t;
typedef struct light_switch_button_s
{
zb_bool_t in_progress;
zb_time_t timestamp;
} light_switch_button_t;
typedef struct light_switch_ctx_s
{
light_switch_bulb_params_t bulb_params;
light_switch_button_t button;
} light_switch_ctx_t;
static zb_void_t find_light_bulb_timeout(zb_uint8_t param);
static light_switch_ctx_t m_device_ctx;
static zb_uint8_t m_attr_zcl_version = ZB_ZCL_VERSION;
static zb_uint8_t m_attr_power_source = ZB_ZCL_BASIC_POWER_SOURCE_UNKNOWN;
static zb_uint16_t m_attr_identify_time = 0;
/* Declare attribute list for Basic cluster. */
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
/* Declare attribute list for Identify cluster. */
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
/* Declare cluster list for Dimmer Switch device (Identify, Basic, Scenes, Groups, On Off, Level Control). */
/* Only clusters Identify and Basic have attributes. */
ZB_HA_DECLARE_DIMMER_SWITCH_CLUSTER_LIST(dimmer_switch_clusters,
basic_attr_list,
identify_attr_list);
/* Declare endpoint for Dimmer Switch device. */
ZB_HA_DECLARE_DIMMER_SWITCH_EP(dimmer_switch_ep,
LIGHT_SWITCH_ENDPOINT,
dimmer_switch_clusters);
/* Declare application's device context (list of registered endpoints) for Dimmer Switch device. */
ZB_HA_DECLARE_DIMMER_SWITCH_CTX(dimmer_switch_ctx, dimmer_switch_ep);
/**@brief Function for the Timer initialization.
*
* @details Initializes the timer module. This creates and starts application timers.
*/
static void timers_init(void)
{
ret_code_t err_code;
// Initialize timer module.
err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for initializing the nrf log module.
*/
static void log_init(void)
{
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}
/**@brief Function for sending ON/OFF requests to the light bulb.
*
* @param[in] param Non-zero reference to ZigBee stack buffer that will be used to construct on/off request.
* @param[in] on_off Requested state of the light bulb.
*/
static zb_void_t light_switch_send_on_off(zb_uint8_t param, zb_uint16_t on_off)
{
zb_uint8_t cmd_id;
zb_buf_t * p_buf = ZB_BUF_FROM_REF(param);
if (on_off)
{
cmd_id = ZB_ZCL_CMD_ON_OFF_ON_ID;
}
else
{
cmd_id = ZB_ZCL_CMD_ON_OFF_OFF_ID;
}
/* if (nrf_gpio_pin_read(IN1) == 1)
{
cmd_id = ZB_ZCL_CMD_ON_OFF_ON_ID;
}
if (nrf_gpio_pin_read(IN1) == 0)
{
cmd_id = ZB_ZCL_CMD_ON_OFF_OFF_ID;
}*/
NRF_LOG_INFO("Send ON/OFF command: %d", on_off);
ZB_ZCL_ON_OFF_SEND_REQ(p_buf,
m_device_ctx.bulb_params.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
m_device_ctx.bulb_params.endpoint,
LIGHT_SWITCH_ENDPOINT,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
cmd_id,
NULL);
}
/**@brief Function for sending step requests to the light bulb.
*
* @param[in] param Non-zero reference to ZigBee stack buffer that will be used to construct step request.
* @param[in] is_step_up Boolean parameter selecting direction of step change.
*/
static zb_void_t light_switch_send_step(zb_uint8_t param, zb_uint16_t is_step_up)
{
zb_uint8_t step_dir;
zb_buf_t * p_buf = ZB_BUF_FROM_REF(param);
if (is_step_up)
{
step_dir = ZB_ZCL_LEVEL_CONTROL_STEP_MODE_UP;
}
else
{
step_dir = ZB_ZCL_LEVEL_CONTROL_STEP_MODE_DOWN;
}
NRF_LOG_INFO("Send step level command: %d", is_step_up);
ZB_ZCL_LEVEL_CONTROL_SEND_STEP_REQ(p_buf,
m_device_ctx.bulb_params.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
m_device_ctx.bulb_params.endpoint,
LIGHT_SWITCH_ENDPOINT,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
NULL,
step_dir,
LIGHT_SWITCH_DIMM_STEP,
LIGHT_SWITCH_DIMM_TRANSACTION_TIME);
}
/**@brief Perform local operation - leave network.
*
* @param[in] param Reference to ZigBee stack buffer that will be used to construct leave request.
*/
static void light_switch_leave_nwk(zb_uint8_t param)
{
zb_ret_t zb_err_code;
/* We are going to leave */
if (param)
{
zb_buf_t * p_buf = ZB_BUF_FROM_REF(param);
zb_zdo_mgmt_leave_param_t * p_req_param;
p_req_param = ZB_GET_BUF_PARAM(p_buf, zb_zdo_mgmt_leave_param_t);
UNUSED_RETURN_VALUE(ZB_BZERO(p_req_param, sizeof(zb_zdo_mgmt_leave_param_t)));
/* Set dst_addr == local address for local leave */
p_req_param->dst_addr = ZB_PIBCACHE_NETWORK_ADDRESS();
p_req_param->rejoin = ZB_FALSE;
UNUSED_RETURN_VALUE(zdo_mgmt_leave_req(param, NULL));
}
else
{
zb_err_code = ZB_GET_OUT_BUF_DELAYED(light_switch_leave_nwk);
ZB_ERROR_CHECK(zb_err_code);
}
}
/**@brief Function for starting join/rejoin procedure.
*
* param[in] leave_type Type of leave request (with or without rejoin).
*/
static zb_void_t light_switch_retry_join(zb_uint8_t leave_type)
{
zb_bool_t comm_status;
if (leave_type == ZB_NWK_LEAVE_TYPE_RESET)
{
comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
ZB_COMM_STATUS_CHECK(comm_status);
}
}
/**@brief Function for leaving current network and starting join procedure afterwards.
*
* @param[in] param Optional reference to ZigBee stack buffer to be reused by leave and join procedure.
*/
static zb_void_t light_switch_leave_and_join(zb_uint8_t param)
{
if (ZB_JOINED())
{
/* Leave network. Joining procedure will be initiated inisde ZigBee stack signal handler. */
light_switch_leave_nwk(param);
}
else
{
/* Already left network. Start joining procedure. */
light_switch_retry_join(ZB_NWK_LEAVE_TYPE_RESET);
if (param)
{
ZB_FREE_BUF_BY_REF(param);
}
}
}
/**@brief Callback function receiving finding procedure results.
*
* @param[in] param Reference to ZigBee stack buffer used to pass received data.
*/
static zb_void_t find_light_bulb_cb(zb_uint8_t param)
{
zb_buf_t * p_buf = ZB_BUF_FROM_REF(param); // Resolve buffer number to buffer address
zb_zdo_match_desc_resp_t * p_resp = (zb_zdo_match_desc_resp_t *) ZB_BUF_BEGIN(p_buf); // Get the begining of the response
zb_apsde_data_indication_t * p_ind = ZB_GET_BUF_PARAM(p_buf, zb_apsde_data_indication_t); // Get the pointer to the parameters buffer, which stores APS layer response
zb_uint8_t * p_match_ep;
zb_ret_t zb_err_code;
if ((p_resp->status == ZB_ZDP_STATUS_SUCCESS) && (p_resp->match_len > 0) && (m_device_ctx.bulb_params.short_addr == 0xFFFF))
{
/* Match EP list follows right after response header */
p_match_ep = (zb_uint8_t *)(p_resp + 1);
/* We are searching for exact cluster, so only 1 EP may be found */
m_device_ctx.bulb_params.endpoint = *p_match_ep;
m_device_ctx.bulb_params.short_addr = p_ind->src_addr;
NRF_LOG_INFO("Found bulb addr: %d ep: %d", m_device_ctx.bulb_params.short_addr, m_device_ctx.bulb_params.endpoint);
zb_err_code = ZB_SCHEDULE_ALARM_CANCEL(find_light_bulb_timeout, ZB_ALARM_ANY_PARAM);
ZB_ERROR_CHECK(zb_err_code);
bsp_board_led_on(BULB_FOUND_LED);
nrf_gpio_pin_set(BULB);
}
if (param)
{
ZB_FREE_BUF_BY_REF(param);
}
}
/**@brief Function for sending ON/OFF and Level Control find request.
*
* @param[in] param Non-zero reference to ZigBee stack buffer that will be used to construct find request.
*/
static zb_void_t find_light_bulb(zb_uint8_t param)
{
zb_buf_t * p_buf = ZB_BUF_FROM_REF(param); // Resolve buffer number to buffer address
zb_zdo_match_desc_param_t * p_req;
/* Initialize pointers inside buffer and reserve space for zb_zdo_match_desc_param_t request */
UNUSED_RETURN_VALUE(ZB_BUF_INITIAL_ALLOC(p_buf, sizeof(zb_zdo_match_desc_param_t) + (1) * sizeof(zb_uint16_t), p_req));
p_req->nwk_addr = MATCH_DESC_REQ_ROLE; // Send to devices specified by MATCH_DESC_REQ_ROLE
p_req->addr_of_interest = MATCH_DESC_REQ_ROLE; // Get responses from devices specified by MATCH_DESC_REQ_ROLE
p_req->profile_id = ZB_AF_HA_PROFILE_ID; // Look for Home Automation profile clusters
/* We are searching for 2 clusters: On/Off and Level Control Server */
p_req->num_in_clusters = 2;
p_req->num_out_clusters = 0;
/*lint -save -e415 // Suppress warning 415 "likely access of out-of-bounds pointer" */
p_req->cluster_list[0] = ZB_ZCL_CLUSTER_ID_ON_OFF;
p_req->cluster_list[1] = ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL;
/*lint -restore */
m_device_ctx.bulb_params.short_addr = 0xFFFF; // Set 0xFFFF to reset short address in order to parse only one response.
UNUSED_RETURN_VALUE(zb_zdo_match_desc_req(param, find_light_bulb_cb));
}
/**@brief Finding procedure timeout handler.
*
* @param[in] param Reference to ZigBee stack buffer that will be used to construct find request.
*/
static zb_void_t find_light_bulb_timeout(zb_uint8_t param)
{
zb_ret_t zb_err_code;
if (param)
{
NRF_LOG_INFO("Bulb not found, try again");
zb_err_code = ZB_SCHEDULE_ALARM(find_light_bulb, param, MATCH_DESC_REQ_START_DELAY);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
ZB_ERROR_CHECK(zb_err_code);
}
else
{
zb_err_code = ZB_GET_OUT_BUF_DELAYED(find_light_bulb_timeout);
ZB_ERROR_CHECK(zb_err_code);
}
}
/**@brief Callback for detecting button press duration.
*
* @param[in] button BSP Button that was pressed.
*/
static zb_void_t light_switch_button_handler(zb_uint8_t button)
{
zb_time_t current_time;
zb_bool_t short_expired;
zb_bool_t on_off;
zb_ret_t zb_err_code;
current_time = ZB_TIMER_GET();
if (button == LIGHT_SWITCH_BUTTON_ON)
{
on_off = ZB_TRUE;
}
else
{
on_off = ZB_FALSE;
}
if (ZB_TIME_SUBTRACT(current_time, m_device_ctx.button.timestamp) > LIGHT_SWITCH_BUTTON_THRESHOLD)
{
short_expired = ZB_TRUE;
}
else
{
short_expired = ZB_FALSE;
}
/* Check if button was released during LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO. */
if (!bsp_button_is_pressed(button))
{
if (!short_expired)
{
/* Allocate output buffer and send on/off command. */
zb_err_code = ZB_GET_OUT_BUF_DELAYED2(light_switch_send_on_off, on_off);
ZB_ERROR_CHECK(zb_err_code);
}
/* Button released - wait for accept next event. */
m_device_ctx.button.in_progress = ZB_FALSE;
}
else
{
if (short_expired)
{
/* The button is still pressed - allocate output buffer and send step command. */
zb_err_code = ZB_GET_OUT_BUF_DELAYED2(light_switch_send_step, on_off);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_LONG_POLL_TMO);
ZB_ERROR_CHECK(zb_err_code);
}
else
{
/* Wait another LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO, until LIGHT_SWITCH_BUTTON_THRESHOLD will be reached. */
zb_err_code = ZB_SCHEDULE_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO);
ZB_ERROR_CHECK(zb_err_code);
}
}
if (nrf_gpio_pin_read(IN1) == 1)
{
on_off = ZB_FALSE;
}
if (nrf_gpio_pin_read(IN1) == 0)
{
on_off = ZB_TRUE;
}
zb_err_code = ZB_GET_OUT_BUF_DELAYED2(light_switch_send_on_off, on_off);
ZB_ERROR_CHECK(zb_err_code);
}
/**@brief Callback for button events.
*
* @param[in] evt Incoming event from the BSP subsystem.
*/
static void buttons_handler(bsp_event_t evt)
{
zb_ret_t zb_err_code;
zb_uint32_t button;
if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
{
/* No bulb found yet. */
return;
}
switch(evt)
{
case BSP_EVENT_KEY_0:
button = LIGHT_SWITCH_BUTTON_ON;
break;
case BSP_EVENT_KEY_1:
button = LIGHT_SWITCH_BUTTON_OFF;
break;
default:
NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
return;
}
if (!m_device_ctx.button.in_progress)
{
m_device_ctx.button.in_progress = ZB_TRUE;
m_device_ctx.button.timestamp = ZB_TIMER_GET();
zb_err_code = ZB_SCHEDULE_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO);
ZB_ERROR_CHECK(zb_err_code);
}
}
/**@brief Function for initializing LEDs and buttons.
*/
static zb_void_t leds_buttons_init(void)
{
ret_code_t error_code;
/* Initialize LEDs and buttons - use BSP to control them. */
error_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
APP_ERROR_CHECK(error_code);
/* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
bsp_board_leds_off();
}
/**@brief Function to set the Sleeping Mode according to the SLEEPY_ON_BUTTON state.
*/
static zb_void_t sleepy_device_setup(void)
{
zb_set_rx_on_when_idle(bsp_button_is_pressed(SLEEPY_ON_BUTTON) ? ZB_FALSE : ZB_TRUE);
}
/**@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_ret_t zb_err_code;
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);
nrf_gpio_pin_set(PAIR_LED);
/* Check the light device address */
if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
{
zb_err_code = ZB_SCHEDULE_ALARM(find_light_bulb, param, MATCH_DESC_REQ_START_DELAY);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
ZB_ERROR_CHECK(zb_err_code);
param = 0; // Do not free buffer - it will be reused by find_light_bulb callback
}
}
else
{
NRF_LOG_ERROR("Failed to join network. Status: %d", status);
bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
nrf_gpio_pin_clear(PAIR_LED);
zb_err_code = ZB_SCHEDULE_ALARM(light_switch_leave_and_join, 0, ZB_TIME_ONE_SECOND);
ZB_ERROR_CHECK(zb_err_code);
}
break;
case ZB_ZDO_SIGNAL_LEAVE:
if (status == RET_OK)
{
bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
nrf_gpio_pin_clear(PAIR_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);
light_switch_retry_join(p_leave_params->leave_type);
}
else
{
NRF_LOG_ERROR("Unable to leave network. Status: %d", status);
}
break;
case ZB_COMMON_SIGNAL_CAN_SLEEP:
zb_sleep_now();
break;
case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
if (status != RET_OK)
{
NRF_LOG_WARNING("Production config is not present or invalid");
}
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);
}
if (param)
{
ZB_FREE_BUF_BY_REF(param);
}
}
/**@brief Function for application main entry.
*/
int main(void)
{
zb_ret_t zb_err_code;
zb_ieee_addr_t ieee_addr;
zb_uint16_t on_off;
/* Initialize timers, loging system and GPIOs. */
timers_init();
log_init();
leds_buttons_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("light_switch");
/* Set device address to the value read from FICR registers. */
zb_osif_get_ieee_eui64(ieee_addr);
zb_set_long_address(ieee_addr);
zb_set_network_ed_role(IEEE_CHANNEL_MASK);
zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
sleepy_device_setup();
/* Initialize application context structure. */
UNUSED_RETURN_VALUE(ZB_MEMSET(&m_device_ctx, 0, sizeof(light_switch_ctx_t)));
/* Set default bulb short_addr. */
m_device_ctx.bulb_params.short_addr = 0xFFFF;
/* Register dimmer switch device context (endpoints). */
ZB_AF_REGISTER_DEVICE_CTX(&dimmer_switch_ctx);
/** Start Zigbee Stack. */
zb_err_code = zboss_start();
ZB_ERROR_CHECK(zb_err_code);
nrf_802154_tx_power_set(TX_POWER_LEVEL);
nrf_gpio_cfg_output(PAIR_LED);
nrf_gpio_cfg_output(BULB);
nrf_gpio_cfg_sense_input(IN1,NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_HIGH);
while(1)
{
zboss_main_loop_iteration();
UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
}
}
/**
* @}
*/
light_switch.c
regards,
jagadeesh