diff options
Diffstat (limited to 'Projects/P-NUCLEO-WB55.Nucleo/Applications/Zigbee/Zigbee_OnOff_Router/STM32_WPAN/App/app_zigbee_demo.c')
-rw-r--r-- | Projects/P-NUCLEO-WB55.Nucleo/Applications/Zigbee/Zigbee_OnOff_Router/STM32_WPAN/App/app_zigbee_demo.c | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/Projects/P-NUCLEO-WB55.Nucleo/Applications/Zigbee/Zigbee_OnOff_Router/STM32_WPAN/App/app_zigbee_demo.c b/Projects/P-NUCLEO-WB55.Nucleo/Applications/Zigbee/Zigbee_OnOff_Router/STM32_WPAN/App/app_zigbee_demo.c new file mode 100644 index 000000000..1b9c9cb92 --- /dev/null +++ b/Projects/P-NUCLEO-WB55.Nucleo/Applications/Zigbee/Zigbee_OnOff_Router/STM32_WPAN/App/app_zigbee_demo.c @@ -0,0 +1,402 @@ +/** + ****************************************************************************** + * File Name : App/app_zigbee.c + * Description : Zigbee Application. + ****************************************************************************** + * @attention + * + * <h2><center>© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.</center></h2> + * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include <assert.h> +#include "app_common.h" +#include "app_entry.h" +#include "dbg_trace.h" +#include "app_zigbee.h" +#include "shci.h" +#include "stm_logging.h" +#include "app_conf.h" +#include "stm32wbxx_core_interface_def.h" +#include "zigbee_types.h" +#include "zigbee_interface.h" +#include "stm32_seq.h" +#include "zcl/zcl.h" +#include "zcl/zcl.onoff.h" +#include "zcl/zcl.identify.h" + +/* Startup Configuration -----------------------------------------------------*/ +#define APP_STARTUP_DISTRIB 0 /* Distributed Netork*/ +#define APP_STARTUP_TOUCHLINK_TARGET 1 /* Touchlink Target*/ +#define APP_STARTUP_TOUCHLINK_INITIATOR 2 /* Touchlink Initiator */ +#define APP_STARTUP_CENTRALIZED_COORD 3 /* Centralized Network Coordinator */ +#define APP_STARTUP_CENTRALIZED_ROUTER 4 /* Centralized Network Router */ + +/* Choose the startup type you want from the options above */ +#define APP_STARTUP_TYPE APP_STARTUP_CENTRALIZED_ROUTER + +/* Spec is -40 dBm, but use -60 for ease of testing, and until we get real RSSI from STMAC. */ +#define APP_TOUCHLINK_MIN_RSSI -60 + +/* Private defines -----------------------------------------------------------*/ +#define APP_ZIGBEE_STARTUP_FAIL_DELAY 3000U + +#define SW1_ENDPOINT 17 +#define SW2_ENDPOINT 18 +#define TOUCHLINK_ENDPOINT 200 /* arbitrary */ + +#define SW1_GROUP_ADDR 0x0001 +#define SW2_GROUP_ADDR 0x0002 + +#define SW1_FLAG 0x01 +#define SW2_FLAG 0x02 + +#define SW1_LED LED_RED +#define SW2_LED LED_GREEN +#define SW3_LED LED_BLUE + +#define CHANNEL 15 +/* Private function prototypes -----------------------------------------------*/ + +/* Private variables -----------------------------------------------*/ +struct zigbee_demo_info { + bool has_init; + struct ZigBeeT *zb; + enum ZbStartType startupControl; + enum ZbStatusCodeT join_status; + uint32_t join_delay; + bool init_after_join; + + struct ZbZclClusterT *onoff_server_1; + struct ZbZclClusterT *onoff_client_1; + struct ZbZclClusterT *identify_server_1; + + struct ZbZclClusterT *onoff_server_2; + struct ZbZclClusterT *onoff_client_2; + + uint8_t sw_flags; +}; + +static struct zigbee_demo_info zigbee_demo_info; + +static enum ZclStatusCodeT onoff_server_attr_cb(struct ZbZclClusterT *clusterPtr, struct ZbZclAttrCbInfoT *cb); + +static const struct ZbZclAttrT onoff_server_attr_list[] = { + /* OnOff Server Attributes */ + { + ZCL_ONOFF_ATTR_ONOFF, ZCL_DATATYPE_BOOLEAN, + ZCL_ATTR_FLAG_REPORTABLE | ZCL_ATTR_FLAG_PERSISTABLE | ZCL_ATTR_FLAG_DEFAULTABLE | ZCL_ATTR_FLAG_CB_NOTIFY, 0, + onoff_server_attr_cb, {0, 0}, {0, 0} + }, +}; + +/* Functions Definition ------------------------------------------------------*/ + +static enum ZclStatusCodeT onoff_server_attr_cb(struct ZbZclClusterT *clusterPtr, struct ZbZclAttrCbInfoT *cb) +{ + uint8_t endpoint; + uint8_t attrVal; + + endpoint = ZbZclClusterGetEndpoint(clusterPtr); + switch (cb->info->attributeId) { + case ZCL_ONOFF_ATTR_ONOFF: + if (endpoint == SW1_ENDPOINT) { + if (ZbZclAttrRead(zigbee_demo_info.onoff_server_1, ZCL_ONOFF_ATTR_ONOFF, NULL, &attrVal, sizeof(attrVal), false) == ZCL_STATUS_SUCCESS) { + if (attrVal != 0) { + APP_DBG("SW1_LED ON"); + BSP_LED_On(SW1_LED); + } + else { + APP_DBG("SW1_LED OFF"); + BSP_LED_Off(SW1_LED); + } + } + } + else if (endpoint == SW2_ENDPOINT) { + if (ZbZclAttrRead(zigbee_demo_info.onoff_server_2, ZCL_ONOFF_ATTR_ONOFF, NULL, &attrVal, sizeof(attrVal), false) == ZCL_STATUS_SUCCESS) { + if (attrVal != 0) { + APP_DBG("SW2_LED ON"); + BSP_LED_On(SW2_LED); + } + else { + APP_DBG("SW2_LED OFF"); + BSP_LED_Off(SW2_LED); + } + } + } + break; + + default: + break; + } /* switch */ + return ZCL_STATUS_SUCCESS; +} /* onoff_server_attr_notify */ + +static void config_endpoints(void) +{ + ZbApsmeAddEndpointReqT req; + ZbApsmeAddEndpointConfT conf; + + memset(&req, 0, sizeof(req)); + req.profileId = ZCL_PROFILE_HOME_AUTOMATION; + req.deviceId = ZCL_DEVICE_ONOFF_SWITCH; + + /* Endpoint: SW1_ENDPOINT */ + req.endpoint = SW1_ENDPOINT; + ZbZclAddEndpoint(zigbee_demo_info.zb, &req, &conf); + assert(conf.status == ZB_STATUS_SUCCESS); + /* OnOff Server */ + zigbee_demo_info.onoff_server_1 = ZbZclOnOffServerAlloc(zigbee_demo_info.zb, SW1_ENDPOINT, NULL); + assert(zigbee_demo_info.onoff_server_1 != NULL); + ZbZclAttrAppendList(zigbee_demo_info.onoff_server_1, onoff_server_attr_list, ZCL_ATTR_LIST_LEN(onoff_server_attr_list)); + ZbZclClusterEndpointRegister(zigbee_demo_info.onoff_server_1); + /* OnOff Client */ + zigbee_demo_info.onoff_client_1 = ZbZclOnOffClientAlloc(zigbee_demo_info.zb, SW1_ENDPOINT); + assert(zigbee_demo_info.onoff_client_1 != NULL); + ZbZclClusterEndpointRegister(zigbee_demo_info.onoff_client_1); + /* Identify Server for Touchlink */ + zigbee_demo_info.identify_server_1 = ZbZclIdentifyServerAlloc(zigbee_demo_info.zb, SW1_ENDPOINT, NULL); + assert(zigbee_demo_info.identify_server_1 != NULL); + + /* Endpoint: SW2_ENDPOINT */ + req.endpoint = SW2_ENDPOINT; + ZbZclAddEndpoint(zigbee_demo_info.zb, &req, &conf); + assert(conf.status == ZB_STATUS_SUCCESS); + /* OnOff Server */ + zigbee_demo_info.onoff_server_2 = ZbZclOnOffServerAlloc(zigbee_demo_info.zb, SW2_ENDPOINT, NULL); + assert(zigbee_demo_info.onoff_server_2 != NULL); + ZbZclAttrAppendList(zigbee_demo_info.onoff_server_2, onoff_server_attr_list, ZCL_ATTR_LIST_LEN(onoff_server_attr_list)); + ZbZclClusterEndpointRegister(zigbee_demo_info.onoff_server_2); + /* OnOff Client */ + zigbee_demo_info.onoff_client_2 = ZbZclOnOffClientAlloc(zigbee_demo_info.zb, SW2_ENDPOINT); + assert(zigbee_demo_info.onoff_client_2 != NULL); + ZbZclClusterEndpointRegister(zigbee_demo_info.onoff_client_2); +} /* config_endpoints */ + +static void config_group_addr(void) +{ + ZbApsmeAddGroupReqT req; + ZbApsmeAddGroupConfT conf; + + memset(&req, 0, sizeof(req)); + req.endpt = SW1_ENDPOINT; + req.groupAddr = SW1_GROUP_ADDR; + ZbApsmeAddGroupReq(zigbee_demo_info.zb, &req, &conf); + + req.endpt = SW2_ENDPOINT; + req.groupAddr = SW2_GROUP_ADDR; + ZbApsmeAddGroupReq(zigbee_demo_info.zb, &req, &conf); +} /* config_group_addr */ + +/** + * @brief Zigbee Demo Task + * @param None + * @retval None + */ +void APP_ZIGBEE_Demo(void) +{ + /* + * Handle Initialization + */ + if (!zigbee_demo_info.has_init) { + zigbee_demo_info.sw_flags = 0; + + zigbee_demo_info.zb = ZbInit(0U, NULL, NULL); + assert(zigbee_demo_info.zb != NULL); + + /* Create the endpoint and cluster(s) */ + config_endpoints(); + + BSP_LED_Off(SW1_LED); + BSP_LED_Off(SW2_LED); + BSP_LED_Off(SW3_LED); + + /* Configure the joining parameters */ + zigbee_demo_info.join_status = 0x01; /* init to error status */ + zigbee_demo_info.join_delay = HAL_GetTick(); /* now */ + zigbee_demo_info.startupControl = ZbStartTypeJoin; + + /* Initialization Complete */ + zigbee_demo_info.has_init = true; + } + + /* + * Handle Network Joining / Forming + */ + if ((zigbee_demo_info.join_status != ZB_STATUS_SUCCESS) && (HAL_GetTick() >= zigbee_demo_info.join_delay)) { + struct ZbStartupT config; + enum ZbStatusCodeT status; + + /* Configure Zigbee Logging (only need to do this once, but this is a good place to put it) */ + ZbSetLogging(zigbee_demo_info.zb, ZB_LOG_MASK_LEVEL_5, NULL); + + /* Attempt to join a zigbee network */ + ZbStartupConfigGetProDefaults(&config); + + + APP_DBG("Network config : APP_STARTUP_CENTRALIZED_ROUTER"); + config.startupControl = ZbStartTypeJoin; + + /* Using the default HA preconfigured Link Key */ + memcpy(config.security.preconfiguredLinkKey, sec_key_ha, ZB_SEC_KEYSIZE); + + config.channelList.count = 1; + config.channelList.list[0].page = 0; + config.channelList.list[0].channelMask = WPAN_CHANNELMASK_2400MHZ; + + /* Using ZbStartupWait (blocking) here instead of ZbStartup, in order to demonstrate how to do + * a blocking call on the M4. */ + status = ZbStartupWait(zigbee_demo_info.zb, &config); + + APP_DBG("ZbStartup Callback (status = 0x%02x)", status); + zigbee_demo_info.join_status = status; + + if (status == ZB_STATUS_SUCCESS) { + zigbee_demo_info.join_delay = 0U; + zigbee_demo_info.init_after_join = true; + BSP_LED_On(SW3_LED); + } + else { + APP_DBG("Startup failed, attempting again after a short delay."); + zigbee_demo_info.join_delay = HAL_GetTick() + APP_ZIGBEE_STARTUP_FAIL_DELAY; + } + } + + /* + * Handle Application (Switches and LEDs) + */ + if (zigbee_demo_info.join_status == ZB_STATUS_SUCCESS) { + /* Check if we just joined */ + if (zigbee_demo_info.init_after_join) { + zigbee_demo_info.init_after_join = false; + + /* Assign ourselves to the group addresses */ + config_group_addr(); + + /* Since we're using group addressing (broadcast), shorten the broadcast timeout */ + uint32_t bcast_timeout = 3; + ZbNwkSet(zigbee_demo_info.zb, ZB_NWK_NIB_ID_NetworkBroadcastDeliveryTime, &bcast_timeout, sizeof(bcast_timeout)); + } + + /* Check for switch flags */ + if (zigbee_demo_info.sw_flags != 0) { + struct ZbApsAddrT dst; + + memset(&dst, 0, sizeof(dst)); + dst.mode = ZB_APSDE_ADDRMODE_GROUP; + + if ((zigbee_demo_info.sw_flags & SW1_FLAG) != 0) { + dst.endpoint = SW1_ENDPOINT; + dst.nwkAddr = SW1_GROUP_ADDR; + + APP_DBG("SW1 PUSHED (SENDING TOGGLE TO GROUP 0x0001)"); + if (ZbZclOnOffClientToggleReq(zigbee_demo_info.onoff_client_1, &dst, NULL, NULL) != ZB_STATUS_SUCCESS) { + APP_DBG("Error, ZbZclOnOffClientToggleReq failed (SW1_ENDPOINT)"); + } + /* We will get a loopback message because we belong to the same APS Group, + * causing our own local LED to toggle. */ + } + + if ((zigbee_demo_info.sw_flags & SW2_FLAG) != 0) { + dst.endpoint = SW2_ENDPOINT; + dst.nwkAddr = SW2_GROUP_ADDR; + + APP_DBG("SW2 PUSHED (SENDING TOGGLE TO GROUP 0x0002)"); + if (ZbZclOnOffClientToggleReq(zigbee_demo_info.onoff_client_2, &dst, NULL, NULL) != ZB_STATUS_SUCCESS) { + APP_DBG("Error, ZbZclOnOffClientToggleReq failed (SW2_ENDPOINT)"); + } + /* We will get a loopback message because we belong to the same APS Group, + * causing our own local LED to toggle. */ + } + + /* Clear the flags */ + zigbee_demo_info.sw_flags = 0; + } + + } + + UTIL_SEQ_SetTask(1U << CFG_TASK_ZIGBEE_APP, CFG_SCH_PRIO_0); +} /* APP_ZIGBEE_Demo */ + +/************************************************************* + * ZbStartupWait Blocking Call + *************************************************************/ + +struct ZbStartupWaitInfo { + bool active; + enum ZbStatusCodeT status; +}; + +static void ZbStartupWaitCb(enum ZbStatusCodeT status, void *cb_arg) +{ + struct ZbStartupWaitInfo *info = cb_arg; + + info->status = status; + info->active = false; +} /* ZbStartupWaitCb */ + +enum ZbStatusCodeT ZbStartupWait(struct ZigBeeT *zb, struct ZbStartupT *config) +{ + struct ZbStartupWaitInfo *info; + enum ZbStatusCodeT status; + + info = malloc(sizeof(struct ZbStartupWaitInfo)); + if (info == NULL) { + return ZB_STATUS_ALLOC_FAIL; + } + memset(info, 0, sizeof(struct ZbStartupWaitInfo)); + + info->active = true; + status = ZbStartup(zb, config, ZbStartupWaitCb, info); + if (status != ZB_STATUS_SUCCESS) { + info->active = false; + return status; + } + while (info->active) { + UTIL_SEQ_Run( UTIL_SEQ_DEFAULT ); + } + status = info->status; + free(info); + return status; +} /* ZbStartupWait */ + +/************************************************************* + * External Interrupt Handler + *************************************************************/ + +/** + * @brief This function manage the Push button action + * @param GPIO_Pin : GPIO pin which has been activated + * @retval None + */ +void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) +{ + switch (GPIO_Pin) { + case BUTTON_SW1_PIN: + zigbee_demo_info.sw_flags |= SW1_FLAG; + break; + + case BUTTON_SW2_PIN: + zigbee_demo_info.sw_flags |= SW2_FLAG; + break; + + case BUTTON_SW3_PIN: + APP_DBG("SW3 PUSHED (LOCAL LEDS OFF)"); + ZbZclAttrIntegerWrite(zigbee_demo_info.onoff_server_1, ZCL_ONOFF_ATTR_ONOFF, 0); + ZbZclAttrIntegerWrite(zigbee_demo_info.onoff_server_2, ZCL_ONOFF_ATTR_ONOFF, 0); + break; + + default: + break; + } +} /* HAL_GPIO_EXTI_Callback */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |