#include "user.h"
#include PROJECT_H
#include "ikk-token.h"
#include "ikk-opt-tunnel.h"
#include "ikk-factory-test.h"
#include "ikk-cluster.h"
#include "ikk-pwm.h"
#include "ikk-timer.h"
#include "ikk-uart.h"
#include "ikk-relay.h"
#include "ikk-led.h"
#include "ikk-network.h"
#include "ikk-command.h"
#include "ikk-common-utils.h"
#include "ikk-interpan.h"
#include "ikk-ota.h"

//#define		SINGLE_LIGHT_PANEL
//#define 		DUAL_LIGHT_PANEL
//#define		THREE_LIGHT_PANEL
#define		FOUR_LIGHT_PANEL

#ifdef SINGLE_LIGHT_PANEL
#define 	g_ucRelayTotalNum  1
#endif

#ifdef DUAL_LIGHT_PANEL
#define 	g_ucRelayTotalNum  2
#endif

#ifdef THREE_LIGHT_PANEL
#define 	g_ucRelayTotalNum  3
#endif

#ifdef FOUR_LIGHT_PANEL
#define 	g_ucRelayTotalNum  4
#endif

#define ZERO_PIN		GPIO_PA0

#define RELAY1_PIN		GPIO_PC0
#define RELAY2_PIN		GPIO_PC4
#define RELAY3_PIN		GPIO_PC6
#define RELAY4_PIN		GPIO_PC5

#define LED_RADAR_PIN	GPIO_PD4
#define LED1_PIN		GPIO_PB5
#define LED2_PIN		GPIO_PA4
#define LED3_PIN		GPIO_PD2
#define LED4_PIN		GPIO_PA3

#define KEY_SYS_PIN		GPIO_PD7
#define KEY1_PIN		GPIO_PC7
#define KEY2_PIN		GPIO_PB4
#define KEY3_PIN		GPIO_PD3
#define KEY4_PIN		GPIO_PA6
#define RADAR_PIN		GPIO_PC1


#define UART_TX_PIN		GPIO_PB7
#define UART_RX_PIN		GPIO_PB1
#define SYS_BUTTON_LONG_PRESS_TIME_MS			(5 * 1000)
#define DELAY_REPORT_DATA_AFTER_NWK_JOINED_MS	(3 * 1000)

#define HEART_RAND_MIN_NUM						(240 * 1000)
#define HEART_RAND_MAX_NUM						(300 * 1000)

#define LED_SLOW_BLINK_ON_TIME_MS				800
#define LED_SLOW_BLINK_OFF_TIME_MS				800
#define LED_FAST_BLINK_ON_TIME_MS				200
#define LED_FAST_BLINK_OFF_TIME_MS				200

#define LED_SLOW_BLINK_CONTINUE_TIME_MS			(60 * 1000)
#define LED_FAST_BLINK_CONTINUE_TIME_MS			(5 * 1000)

#define MIN_JOINED_NWK_DELAY_TIME_MS 			(7 * 1000) //重新上电后最短时间，用于判断是否随机延时10~40S上报心跳和CMEI和ISN

#define REPORT_ATTR_MAX_RAND_NUM				(5 * 1000) //场景下发控制后随机最大延时上报状态,状态改变后SDK会主动上报
#define REPORT_ATTR_MIN_RAND_NUM				(2 * 1000) //场景下发控制后随机最小延时上报状态


#define CHECKED_ZERO_DELAY_ON_TIME_MS			(6000)//因继电器会有延时，检测到零点后，按键开关或命令下发开关延时去开的时间，
#define CHECKED_ZERO_DELAY_OFF_TIME_MS			(5970)//因继电器会有延时，检测到零点后，按键开关或命令下发开关延时去关的时间，
//join nwk timeout
#define NWK_STEERING_TIMEOUT_MS 				(60 * 1000)

#define HEART_DEBUG 							0
#if HEART_DEBUG
#define HEARTBEAT_TIME_MS						(20 * 1000)
#else
#define HEARTBEAT_TIME_MS						kGetRandNum(HEART_RAND_MIN_NUM, HEART_RAND_MAX_NUM)
#endif

#define RADAR_ON_TIME_MS						10000
#define SENSOR_LONG_PRESS_TIME_MS				200
#define MAX_FIRST_USER_KEY_LEAVE_NWK_INTERVAL_TIME_MS (14 * 1000)//第一个按键长按两次退网最大间隔时间

typedef enum {KEY_SYS_ID = 1,KEY1_ID, KEY2_ID, KEY3_ID, KEY4_ID , RADAR_ID}KEY_ID_ENUM;
typedef enum {LED_RADAR_ID = 1,LED1_ID, LED2_ID, LED3_ID, LED4_ID, LED_ALL_ID}LED_ID_ENUM;
typedef enum {RELAY_CHANNEL1_ID=1, RELAY_CHANNEL2_ID, RELAY_CHANNEL3_ID, RELAY_CHANNEL4_ID, RELAY_ALL_ID}RELAY_ID_ENUM;

#define GET_LED_ID(endpoint) 	(endpoint == 1?LED1_ID:(endpoint == 2?LED2_ID:(endpoint == 3?LED3_ID:LED4_ID)))
#define GET_ENDPOINT(led_id) 	(led_id == LED1_ID?1:(led_id == LED2_ID?2:(led_id == LED3_ID?3:4)))
#define GET_LED_ID_BY_ENDPOINT(endpoint, max_endpint) 	(endpoint <= max_endpint?GET_LED_ID(endpoint):LED_UNKNOW_ID)
// BUTTONs CONFIG
BtnConfSt g_btnConfList[] = {
	{KEY_SYS_ID, 	KEY_SYS_PIN, 	EBP_HIGH, false, true, SYS_BUTTON_LONG_PRESS_TIME_MS},	// Key1
#ifdef SINGLE_LIGHT_PANEL
	{KEY1_ID, 		KEY2_PIN, 		EBP_HIGH, false, true, SYS_BUTTON_LONG_PRESS_TIME_MS},	// Key2
#endif

#ifdef DUAL_LIGHT_PANEL
	{KEY1_ID, 		KEY2_PIN, 		EBP_HIGH, false, true, SYS_BUTTON_LONG_PRESS_TIME_MS},	// Key2
	{KEY2_ID, 		KEY4_PIN, 		EBP_HIGH, false, false, 0xffffffff},	// Key2
#endif

#ifdef THREE_LIGHT_PANEL
	{KEY1_ID, 		KEY1_PIN, 		EBP_HIGH, false, true, SYS_BUTTON_LONG_PRESS_TIME_MS},	// Key2
	{KEY2_ID, 		KEY2_PIN, 		EBP_HIGH, false, false, 0xffffffff},	// Key2
	{KEY3_ID, 		KEY3_PIN, 		EBP_HIGH, false, false, 0xffffffff},	// Key2
#endif

#ifdef FOUR_LIGHT_PANEL
	{KEY1_ID, 		KEY1_PIN, 		EBP_HIGH, false, true, SYS_BUTTON_LONG_PRESS_TIME_MS},	// Key2
	{KEY2_ID, 		KEY2_PIN, 		EBP_HIGH, false, false, 0xffffffff},	// Key2
	{KEY3_ID, 		KEY3_PIN, 		EBP_HIGH, false, false, 0xffffffff},	// Key2
	{KEY4_ID, 		KEY4_PIN, 		EBP_HIGH, false, false, 0xffffffff},	// Key2
#endif
};
// LEDs CONFIG
LedConfSt g_ledConfList[] = {
	{(uint8_t)LED_RADAR_ID, 1,  {LED_RADAR_PIN, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
#ifdef SINGLE_LIGHT_PANEL
	{(uint8_t)LED1_ID, 		1, 	{LED2_PIN, PWM1_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED_ALL_ID, 	1,  {LED2_PIN, PWM1_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
#endif

#ifdef DUAL_LIGHT_PANEL
	{(uint8_t)LED1_ID, 		1, 	{LED2_PIN, PWM1_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED2_ID, 		1, 	{LED4_PIN, PWM2_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED_ALL_ID, 	2,  {LED2_PIN, PWM1_ID, LED4_PIN, PWM2_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
#endif

#ifdef THREE_LIGHT_PANEL
	{(uint8_t)LED1_ID, 		1, 	{LED1_PIN, PWM1_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED2_ID, 		1, 	{LED2_PIN, PWM2_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED3_ID, 		1, 	{LED3_PIN, PWM3_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED_ALL_ID, 	3,  {LED1_PIN, PWM1_ID, LED2_PIN, PWM2_ID, LED3_PIN, PWM3_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
#endif

#ifdef FOUR_LIGHT_PANEL
	{(uint8_t)LED1_ID, 		1, 	{LED1_PIN, PWM1_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED2_ID, 		1, 	{LED2_PIN, PWM2_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED3_ID, 		1, 	{LED3_PIN, PWM3_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED4_ID, 		1, 	{LED4_PIN, PWM4_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID, PIN_UNKNOW, PWM_UNKNOW_ID}, ELP_HIGH },
	{(uint8_t)LED_ALL_ID, 	4,  {LED1_PIN, PWM1_ID, LED2_PIN, PWM2_ID, LED3_PIN, PWM3_ID, LED4_PIN, PWM4_ID}, ELP_HIGH },
#endif
};
PwmConfSt g_pwmConfList[] = {
#ifdef SINGLE_LIGHT_PANEL
	{PWM1_ID, {LED2_PIN, KK_PWM_CC1}},	//
#endif

#ifdef DUAL_LIGHT_PANEL
	{PWM1_ID, {LED2_PIN, KK_PWM_CC0}},	//
	{PWM2_ID, {LED4_PIN, KK_PWM_CC1}},	//
#endif

#ifdef THREE_LIGHT_PANEL
	{PWM1_ID, {LED1_PIN, KK_PWM_CC0}},	//
	{PWM2_ID, {LED2_PIN, KK_PWM_CC1}},	//
	{PWM3_ID, {LED3_PIN, KK_PWM_CC2}},	//
#endif

#ifdef FOUR_LIGHT_PANEL
	{PWM1_ID, {LED1_PIN, KK_PWM_CC0}},	//
	{PWM2_ID, {LED2_PIN, KK_PWM_CC1}},	//
	{PWM3_ID, {LED3_PIN, KK_PWM_CC2}},	//
	{PWM4_ID, {LED4_PIN, KK_PWM_CC3}},	//
#endif
};

// ZERO-ACCESS CONFIG
RelayChannelConfSt g_relayConfList[] = {
	{RELAY_CHANNEL1_ID, 1, {RELAY1_PIN, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW}, EZAP_HIGH },	// Channel1
	{RELAY_CHANNEL2_ID, 1, {RELAY2_PIN, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW}, EZAP_HIGH },	// Channel2
	{RELAY_CHANNEL3_ID, 1, {RELAY3_PIN, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW}, EZAP_HIGH },	// Channel3
	{RELAY_CHANNEL4_ID, 1, {RELAY4_PIN, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW}, EZAP_HIGH },	// Channel3
	{RELAY_ALL_ID, 		4, {RELAY1_PIN, RELAY2_PIN, RELAY3_PIN, RELAY4_PIN, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW, PIN_UNKNOW}, EZAP_HIGH },	//ALL
};

//老化配置
FactoryTestConfSt g_factoryTestConfList[] = {
		{KEY_SYS_ID, LONG_PRESS_1_TIMES, MECHANICAL_KEY_LONG_PRESS_TIME_MS},
		{KEY1_ID, LONG_PRESS_1_TIMES, MECHANICAL_KEY_LONG_PRESS_TIME_MS},
};
BindObjSt cluster_obj_list[] = {
#ifdef SINGLE_LIGHT_PANEL
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  1},
#endif

#ifdef DUAL_LIGHT_PANEL
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  1},
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  2},
#endif

#ifdef THREE_LIGHT_PANEL
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  1},
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  2},
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  3},
#endif

#ifdef FOUR_LIGHT_PANEL
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  1},
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  2},
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  3},
	{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF,  4},
#endif
	{ZCL_CLUSTER_PRIVATE_FCC0, ZCL_ATTRID_NoDisturbMode,  1},
	{ZCL_CLUSTER_GEN_DIAGNOSTICS, ZCL_DIAGNOSTICS_ATTRID_LAST_MESSAGE_RSSI,  1},
};

void pOnOffAttributeChangeCallback(uint8_t endpoint,uint16_t cluster,uint16_t attribute,uint8_t *data,uint8_t data_type);

AttributeChangeConfSt attribte_change_list[] = {
	{ZCL_CLUSTER_GEN_ON_OFF, pOnOffAttributeChangeCallback},
};
uint32_t u32PeroidIntervalMS   = 2*1000;
bool Human_body_induction_flag = false;
static bool power_on_sync[4] = {false,false,false,false};
#define GET_MAX_ENDPOINT(relay_num)  (relay_num)

static uint8_t g_u8NoDisturbModeMinLevel  = 0x01;
static uint8_t g_u8NoDisturbModeMaxLevel    = 0x64;
//非控客网关首次数据是否上报标志
static bool g_bIsNotKonkeGatewayFirstReportedFlg = false;
static uint8_t g_u8CurrentHeartEndpoint = 1;
static uint8_t g_ucRelayIdBuff[] = {RELAY_CHANNEL1_ID, RELAY_CHANNEL2_ID, RELAY_CHANNEL3_ID, RELAY_CHANNEL4_ID, RELAY_ALL_ID};
void JoinCompleteCallback(NwkJoinCompltEnum nwkcomplt );
void kUserNetworkStatusNotify(NwkStatusEnum nwkst );
void kUserNetworkExitCompleteCallback(void);
void kUserOnOffClusterOnOffStatusCallback(uint8_t endpoint, OnOffStatusEnum estatus );
kk_err_t kUserOODMessageIncoming(uint8_t channel, uint8_t opcode, uint8_t args_in_out[], uint8_t *length_in_out );

void kUserButtonAcitonCallback(unsigned char button_id, BtnActionEnum action );
void kUserLedActionDoneCallback(unsigned char id);
void kUserPwmActionDoneCallback(unsigned char id, PwmGradientDirectionEnum opt);
#if Z30_DEVICE_AGING_ENABLE
void kUserFactorTestPollCallback(FactoryTestStatusEnum status);
#endif

#if Z30_DEVICE_OTA_ENABLE
void kOTAMoudleUserCallback(OTAStatusEnum status);
#endif

#define UART_ENABLE			true
void kUserRelayLedCallback(RelayStatusSt status);
void kRadarDetectInit(void);
void kRadarLedTragger(void);
void kSetLedStatus(LED_ID_ENUM id);
#if UART_ENABLE
void UartMsgProcessHandle(UMsgNodeSt *pMsgNode);
bool MsgCRC16(uint8_t *pdat, int length );
uint16_t check_sum( uint8_t* msg, uint8_t len);
uint8_t uart_send(void);
#endif

static ev_timer_event_t *kkSystemSetUpEvent = NULL;
s32 kkSystemSetUpEventHandler(void *arg );
void kUserInterPanMsgInComingPaser(UMsgNodeSt *pMsgNode);
void pOnOffClusterAttributeChangeCallback(uint8_t endpoint,uint16_t cluster,uint16_t attribute,uint8_t len,uint8_t *data);

AttributeChangeConfSt  g_ClusterAttributeConfList[] = {
		{ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF, pOnOffClusterAttributeChangeCallback},
};

static bool kEndpointIsValid(uint8_t endpoint);
static void kLEDOnAction(LED_ID_ENUM led_id);
static void kLEDOffAction(LED_ID_ENUM led_id);
void App_Init(void)
{
	iKonkeAfSelfPrint("\r\n************************************************\r\n");
	iKonkeAfSelfPrint("\r\n****************APP   Init***********************\r\n");
	iKonkeAfSelfPrint("\r\n************************************************\r\n");
	#if 1
	kk_err_t err = kBtnModuleInit(g_btnConfList, sizeof(g_btnConfList) / sizeof(BtnConfSt), kUserButtonAcitonCallback);
		if( err != KET_OK ) {
			iKonkeAfSelfPrint("Err: Button Module Init failed(%d)!!\r\n", err);
		}
	#endif
	#if 1
		err = kPwmModuleInit(g_pwmConfList, sizeof(g_pwmConfList)/sizeof(PwmConfSt), kUserPwmActionDoneCallback);
		if( err != KET_OK ) {
			iKonkeAfSelfPrint("Err: PWM Module Init failed(%d)!!\r\n", err);
		}
	#endif
		err = kLedModuleInit(g_ledConfList, sizeof(g_ledConfList) / sizeof(LedConfSt), kUserLedActionDoneCallback);
		if( err != KET_OK ) {
			iKonkeAfSelfPrint("Err: Led Module Init failed(%d)!!\r\n", err);
		}
		err = kRelayModuleInit(ZERO_PIN, CHECKED_ZERO_DELAY_ON_TIME_MS, CHECKED_ZERO_DELAY_OFF_TIME_MS \
				, EZAP_LOW, g_relayConfList,  sizeof(g_relayConfList)/sizeof(RelayChannelConfSt), kUserRelayLedCallback);
		if( err != KET_OK ) {
			iKonkeAfSelfPrint("Err: ZERO Module Init failed(%d)!!\r\n", err);
		}
	#if UART_ENABLE
		uint8_t  recv_header[] = {0xAA,0X55};
		err = kUartModuleInit(UART_TX_PIN,UART_RX_PIN,115200,PARITY_NONE,STOP_BIT_ONE,recv_header,2,3,6,MsgCRC16,UartMsgProcessHandle,true );
	#endif

		kNwkModuleInit(cluster_obj_list,sizeof(cluster_obj_list) / sizeof(cluster_obj_list[0]), kUserNetworkStatusNotify, kUserNetworkExitCompleteCallback);
		//report 4~5 minutes after initialization
		kNwkScheduleTaskRegister(HEARTBEAT_TIME_MS);

#if Z30_DEVICE_OTA_ENABLE
	kOTAMoudleInit(kOTAMoudleUserCallback, LED_ALL_ID);
#endif
#if Z30_DEVICE_AGING_ENABLE
	kFactoryTestInit(kUserFactorTestPollCallback, g_factoryTestConfList, sizeof(g_factoryTestConfList)/ sizeof(FactoryTestConfSt),LED_ALL_ID);
#endif
		// init the private cluster protocol module.
		err =  kOptTunnelModuleInit(kUserOODMessageIncoming);
		if( err != KET_OK ) {
			iKonkeAfSelfPrint("Err: kUserOODMessageIncoming Register Failed(%d)!!\r\n", err);
		}
		// //注册属性改变回调
		ikkAttributeChangeCallbackRegister(attribte_change_list,sizeof(attribte_change_list)/sizeof(attribte_change_list[0]));
		kZclOnOffClusterServerInit(kUserOnOffClusterOnOffStatusCallback);
		if(!ev_timer_exist(kkSystemSetUpEvent)) {
			kkSystemSetUpEvent = TL_ZB_TIMER_SCHEDULE(kkSystemSetUpEventHandler, NULL, 50);
		}
		//start radar detect event
		kRadarDetectInit();

		kZclClusterPermitReportTableInit(cluster_obj_list, sizeof(cluster_obj_list) / sizeof(BindObjSt));
		kOptTunnelTrytoWriteInstallCode();
}

void kUserNetworkExitCompleteCallback()
{
	bool bIsAllOffFlg = true;
	for (uint8_t i = 1; i <= GET_MAX_ENDPOINT(g_ucRelayTotalNum); i++){
		if (kZclOnOffClusterServerOnOffGet(i) == EOOS_ON){
			bIsAllOffFlg = false;
			break;
		}
	}

	if (bIsAllOffFlg == true){
		if (kGetFactoryTestStatus() == FTS_NORMAL ){
			SYSTEM_RESET();
		}
	}
	if (kGetFactoryTestStatus() != FTS_NORMAL ){
		kNwkJoiningStart(NWK_STEERING_TIMEOUT_MS, JoinCompleteCallback);
	}
}
static bool kClustePeriodReportCheckIsSet(uint8_t endpoint)
{
	uint16_t u16MinTimeMS = 0;
	uint16_t u16MaxTimeMS = 0;
	if (endpoint <= Support_Endpoint_Num){
		bool status = kkClusterGetReportingPeriod(endpoint,ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF, &u16MinTimeMS, &u16MaxTimeMS);
		if (status == true){
			if (u16MaxTimeMS > 0){
				return true;
			}
		}
	}
	return false;
}

void JoinCompleteCallback(NwkJoinCompltEnum nwkcomplt )
{
	iKonkeAfSelfPrint("#########JoinCompleteCallback = %d\r\n", nwkcomplt);
	switch(nwkcomplt) {
		case (EJC_JOIN_FAILED ):
		{
			kSetLedStatus(LED_ALL_ID);
			kUserNetworkExitCompleteCallback();
			break;
		}
		case (EJC_JOIN_SUCCEED):
		{
			break;
		}
		default: break;
	}
}

void kUserNetworkStatusNotify(NwkStatusEnum nwkst )
{
	iKonkeAfSelfPrint("#############################kUserNetworkStatusNotify = %d\r\n", nwkst);
	switch(nwkst) {
		case (ENS_ONLINE ):
		{
			uint32_t randTimeMS = DELAY_REPORT_DATA_AFTER_NWK_JOINED_MS;
			//power on after joined network
			uint32_t currentTimeMS = clock_time()/16/1000;
			kSetLedStatus(LED_ALL_ID);

			if ( currentTimeMS < MIN_JOINED_NWK_DELAY_TIME_MS){
				randTimeMS = kGetRandNum(RAND_MIN_NUM, RAND_MAX_NUM);
			}else {
				kLedOptTrigger(LED_ALL_ID, 0, 0, 0, LED_OFF, LED_IGNORE);
#ifdef SINGLE_LIGHT_PANEL
				kPwmOptTrigger(PWM1_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
#endif

#ifdef DUAL_LIGHT_PANEL
				kPwmOptTrigger(PWM2_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
				kPwmOptTrigger(PWM1_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
#endif

#ifdef THREE_LIGHT_PANEL
				kPwmOptTrigger(PWM3_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
				kPwmOptTrigger(PWM2_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
				kPwmOptTrigger(PWM1_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
#endif

#ifdef FOUR_LIGHT_PANEL
				kPwmOptTrigger(PWM4_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
				kPwmOptTrigger(PWM3_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
				kPwmOptTrigger(PWM2_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
				kPwmOptTrigger(PWM1_ID, PWM_TIMER_MAX_DUTY_CYCLE_NUM, 0, 5*1000);
#endif

			}
			if (kIsKonkeRemoteGateway() != true){
				g_bIsNotKonkeGatewayFirstReportedFlg = false;
				kNwkScheduleTaskRegister(randTimeMS);
			}

			iKonkeAfSelfPrint("Joined Network RandTime(%dms) CurrentTime(%d)\r\n", randTimeMS, currentTimeMS);
			break;
		}
		case (ENS_JOINING):
		{
			kLedOptTrigger(LED_ALL_ID, LED_SLOW_BLINK_ON_TIME_MS, LED_SLOW_BLINK_OFF_TIME_MS, \
								LED_SLOW_BLINK_CONTINUE_TIME_MS/(LED_SLOW_BLINK_ON_TIME_MS+LED_SLOW_BLINK_OFF_TIME_MS), LED_ON, LED_IGNORE);
			break;
		}
		case (ENS_LEAVED):
		{
			iKonkeAfSelfPrint("#####Enter Leave\r\n");
			kLedOptTrigger((uint8_t)LED_ALL_ID, LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_OFF_TIME_MS \
						,LED_FAST_BLINK_CONTINUE_TIME_MS/(LED_FAST_BLINK_ON_TIME_MS+LED_FAST_BLINK_OFF_TIME_MS), LED_ON, LED_IGNORE);
			//关闭勿扰模式
			kSetIndicatorNotDisturbModeFlg(false);

			break;
		}
		default:
		{
			break;
		}
	}
}

void pOnOffAttributeChangeCallback(uint8_t endpoint,uint16_t cluster,uint16_t attribute,uint8_t *data,uint8_t data_type)
{
	if((cluster == ZCL_CLUSTER_GEN_ON_OFF)&&(attribute == ZCL_ATTRID_ONOFF)&&(data_type == ZCL_DATA_TYPE_BOOLEAN))
	{
		OnOffStatusEnum estatus = *data;
		kUserOnOffClusterOnOffStatusCallback(endpoint,estatus);
		iKonkeAfSelfPrint("#####pOnOffAttributeChangeCallback,endpont = %d,value = %d\r\n",endpoint,estatus);
	}
}
//on off 属性改变后的回调函数，一般用来操作继电器，过零检测，如果没有过零检测可以在这里同步LED状态
void kUserOnOffClusterOnOffStatusCallback(uint8_t endpoint, OnOffStatusEnum estatus )
{
	iKonkeAfSelfPrint("OnOff-status: endpoint(%d), estatus(%d)\r\n", endpoint, estatus);
	kRadarLedTragger();
	switch(endpoint) {
		case (1):
		{
			kRelayChannelOpt(RELAY_CHANNEL1_ID,estatus == EOOS_OFF? EZAO_OFF : EZAO_ON);
			break;
		}
		case (2):
		{
			kRelayChannelOpt(RELAY_CHANNEL2_ID,estatus == EOOS_OFF? EZAO_OFF : EZAO_ON);
			break;
		}
		case (3):
		{
			kRelayChannelOpt(RELAY_CHANNEL3_ID,estatus == EOOS_OFF? EZAO_OFF : EZAO_ON);
			break;
		}
		case (4):
		{
			kRelayChannelOpt(RELAY_CHANNEL4_ID,estatus == EOOS_OFF? EZAO_OFF : EZAO_ON);
			break;
		}
		default: break;
	}
	kZclOnOffClusterServerOnOffControl(endpoint, estatus);

}

uint8_t  Key_Press_Test_Flag[5]	 = {0};
void kUserButtonAcitonCallback(unsigned char button_id, BtnActionEnum action )
{
	iKonkeAfSelfPrint("kUserButton: ButtonId(%d), Action(%d),%d\r\n", button_id, action,kGetFactoryTestStatus());
	kOptTunneCheckNodeIdIsChangedReport();
	if ( kGetFactoryTestStatus() == FTS_AGING_4HOU || kGetFactoryTestStatus() == FTS_AGING_DONE \
			|| kGetFactoryTestStatus() == FTS_WAITING_RELEASED \
			|| kGetFactoryTestStatus() == FTS_WAITING_SECOND_PRESS \
			|| kNwkIsExiting() == true){
		//未老化完成，单击按键不操作继电器
		return;
	}
	switch(button_id)
	{
		case KEY_SYS_ID:												//sys botton
		{
			switch(action)
			{
				case EBA_CLICK:
				{
					iKonkeAfSelfPrint("SYS_ID!!!!!! kNwkGetCurrentStatus = %d,kInterPanGetEnableStatus = %d\r\n",\
							kNwkGetCurrentStatus(),kInterPanGetEnableStatus(),power_on_sync[0],power_on_sync[1],power_on_sync[2],power_on_sync[3]);
					Key_Press_Test_Flag[0] = 1;
					if(kNwkGetCurrentStatus() == ENS_ONLINE){ // report connected!
						iKonkeAfSelfPrint("Is Online...........\r\n");
						if (kLedIsBlinking(LED_ALL_ID) != true)
							kLedOptTrigger(LED_ALL_ID,  LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_OFF_TIME_MS, 1, LED_ON, LED_OFF);
						if (kIsKonkeRemoteGateway() == true){
							kOptTunnelOODReport(0, 0XCD, NULL, 0);
						}
					}
					else if(kNwkGetCurrentStatus() == ENS_LEAVED)
					{
						if(kGetFactoryTestStatus() == FTS_SINGLE_BOARD_TEST){
							if (kLedIsBlinking(LED_ALL_ID) != true){
								kLedOptTrigger(LED_ALL_ID,  LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_OFF_TIME_MS, 10, LED_ON, LED_OFF);
							    iKonkeAfSelfPrint("######FTS_SINGLE_BOARD_TEST Blinking 10 times######\r\n");
							}
						}else{
							kNwkFactoryReset(false);
							iKonkeAfSelfPrint("Start Joining...........\r\n");
							kNwkJoiningStart(NWK_STEERING_TIMEOUT_MS,JoinCompleteCallback);
						}
					}
				}
					break;
				case EBA_LONGPRESS:
				{
					if(kNwkGetCurrentStatus() == ENS_ONLINE)
					{
						if(kGetInterpanEnableFlg() == true){
							iKonkeAfSelfPrint("Close Interpan...........\r\n");
							kInterpanDisable();
						}
						kNwkFactoryReset(true);
						iKonkeAfSelfPrint("Start Leave...........\r\n");
					}
				}
					break;
				default:
					break;
			}
			break;
		}
		case KEY1_ID:
		{
			if(action == EBA_CLICK)
			{
				iKonkeAfSelfPrint("KEY 1 PRESS!!!\r\n");
				Key_Press_Test_Flag[1] = 1;
				OnOffCtrlEnum state = kZclOnOffClusterServerOnOffGet(1)? EOOC_OFF : EOOC_ON;
				kZclClusterSetPermitReportInfo(1,0x0006,true,false,true,true,NULL,RESET_ENDPOINT);
				//afTest_dataSendDemo();
				kZclOnOffClusterServerOnOffControl(1, state);
			}else if (action == EBA_LONGPRESS){
				if (kNwkIsExiting() == true){
					iKonkeAfSelfPrint("#####NWK is exiting\r\n");
					return;
				}

				if(kGetFactoryTestStatus() == FTS_SINGLE_BOARD_TEST){
					if( kNwkGetCurrentStatus() == ENS_LEAVED ) { // report connected!
						if(kLedIsBlinking(LED_ALL_ID) != true){
							kLedOptTrigger(LED_ALL_ID,  LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_OFF_TIME_MS, 10, LED_ON, LED_OFF);
							iKonkeAfSelfPrint("######FTS_SINGLE_BOARD_TEST Blinking 10 times######\r\n");
						}
					}
				}

				static bool firstLongPressFlg = false;
				if (kNwkGetCurrentStatus() == ENS_ONLINE){
					static uint32_t lastTimeMS = 0;
					uint32_t currentTimeMS = clock_time()/16/1000;
					if (firstLongPressFlg != true \
							|| (currentTimeMS - lastTimeMS >= MAX_FIRST_USER_KEY_LEAVE_NWK_INTERVAL_TIME_MS)){
						firstLongPressFlg = true;
						lastTimeMS = currentTimeMS;
						/*if ( kGetOTAStatus() == OTA_NORMAL){*/
							kLedOptTrigger(LED_ALL_ID,  LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_OFF_TIME_MS, 1, LED_ON, LED_OFF);
						/*}*/
					}else {
						//second times long press
						if (currentTimeMS - lastTimeMS < MAX_FIRST_USER_KEY_LEAVE_NWK_INTERVAL_TIME_MS){
							//关闭黄色LED
//							LED_OPT_OFF(LED_SYS_ID);
							//leave nwk
							if (kNwkGetCurrentStatus() != ENS_JOINING){
								kNwkFactoryReset(true);
							}
						}
						firstLongPressFlg = false;
					}
				}else if (kNwkGetCurrentStatus() == ENS_LEAVED){
					//开始组网
					kNwkFactoryReset(false);
					//steering timeout can be set
					iKonkeAfSelfPrint("#####Start Steering\r\n");
					kNwkJoiningStart(NWK_STEERING_TIMEOUT_MS, JoinCompleteCallback);
				}
			}
			break;
		}
		case (KEY2_ID):
		{
			if (action == EBA_CLICK){
				//restore report attribute immediately
				iKonkeAfSelfPrint("KEY 2 PRESS!!!\r\n");
				Key_Press_Test_Flag[2] = 1;
				OnOffCtrlEnum state = kZclOnOffClusterServerOnOffGet(2)? EOOC_OFF : EOOC_ON;
				kZclClusterSetPermitReportInfo(2,0x0006,true,false,true,true,NULL,RESET_ENDPOINT);
				kZclOnOffClusterServerOnOffControl(2, state);
			}
			break;
		}
		case (KEY3_ID):
		{
			if (action == EBA_CLICK){
				//restore report attribute immediately
				iKonkeAfSelfPrint("KEY 3 PRESS!!!\r\n");
				Key_Press_Test_Flag[3] = 1;
				OnOffCtrlEnum state = kZclOnOffClusterServerOnOffGet(3)? EOOC_OFF : EOOC_ON;
				kZclClusterSetPermitReportInfo(3,0x0006,true,false,true,true,NULL,RESET_ENDPOINT);
				kZclOnOffClusterServerOnOffControl(3, state);
			}
			break;
		}
		case (KEY4_ID):
		{
			if (action == EBA_CLICK){
				//restore report attribute immediately
				iKonkeAfSelfPrint("KEY 4 PRESS!!!\r\n");
				Key_Press_Test_Flag[4] = 1;
				OnOffCtrlEnum state = kZclOnOffClusterServerOnOffGet(4)? EOOC_OFF : EOOC_ON;
				kZclClusterSetPermitReportInfo(4,0x0006,true,false,true,true,NULL,RESET_ENDPOINT);
				kZclOnOffClusterServerOnOffControl(4, state);
			}
			break;
		}
		default:
			break;
	}
}
//过零检测后继电器操作完成，同步LED状态，不是过零操作继电器也是到这里操作LED
void kUserRelayLedCallback(RelayStatusSt status)
{
	iKonkeAfSelfPrint("#########kUserZaLedCallback channel(%d) opt(%d)\r\n", status.u8RelayChannelId, status.opt);

	if (kPwmIsChanging(PWM1_ID) == true || kLedIsBlinking(LED_ALL_ID) == true 	\
			|| kNwkGetCurrentStatus() == ENS_JOINING)
	{
		if(kLedIsBlinking(LED_ALL_ID)){
			for(uint8_t i=0 ;i<g_ucRelayTotalNum;i++)
				if( power_on_sync[i])
					power_on_sync[i] = false;
		}
		return;
	}

	switch (status.u8RelayChannelId)
	{
		case RELAY_CHANNEL1_ID:
			if (kNwkGetCurrentStatus() == ENS_ONLINE || power_on_sync[0] == true \
					|| kGetFactoryTestStatus() == FTS_AGING_4HOU 	\
					|| kGetFactoryTestStatus() == FTS_AGING_DONE 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_RELEASED 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_SECOND_PRESS){
				power_on_sync[0] = false;
				if (status.opt == EZAO_OFF){
					kLEDOffAction(LED1_ID);
				}else if (status.opt == EZAO_ON){
					kLEDOnAction(LED1_ID);
				}
			}else if (kNwkGetCurrentStatus() == ENS_LEAVED \
					|| kNwkGetCurrentStatus() == ENS_OFFLINE){
				if(kZclOnOffClusterServerOnOffGet(1)== EOOC_OFF)
					kLedOptTrigger(LED1_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, EOOC_OFF, EOOC_OFF);
				else
					kLedOptTrigger(LED1_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, LED_ON, LED_ON);
			}
			break;
		case RELAY_CHANNEL2_ID:
			if (kNwkGetCurrentStatus() == ENS_ONLINE || power_on_sync[1] == true \
					|| kGetFactoryTestStatus() == FTS_AGING_4HOU 	\
					|| kGetFactoryTestStatus() == FTS_AGING_DONE 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_RELEASED 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_SECOND_PRESS){
				power_on_sync[1] = false;
				if (status.opt == EZAO_OFF){
					kLEDOffAction(LED2_ID);
				}else if (status.opt == EZAO_ON){
					kLEDOnAction(LED2_ID);
				}
			}else if (kNwkGetCurrentStatus() == ENS_LEAVED \
					|| kNwkGetCurrentStatus() == ENS_OFFLINE){
				if(kZclOnOffClusterServerOnOffGet(2)== EOOC_OFF)
					kLedOptTrigger(LED2_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, EOOC_OFF, EOOC_OFF);
				else
					kLedOptTrigger(LED2_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, LED_ON, LED_ON);
			}
			break;
		case RELAY_CHANNEL3_ID:
			if (kNwkGetCurrentStatus() == ENS_ONLINE  || power_on_sync[2] == true \
					|| kGetFactoryTestStatus() == FTS_AGING_4HOU 	\
					|| kGetFactoryTestStatus() == FTS_AGING_DONE 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_RELEASED 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_SECOND_PRESS){
				power_on_sync[2] = false;
				if (status.opt == EZAO_OFF){
					kLEDOffAction(LED3_ID);
				}else if (status.opt == EZAO_ON){
					kLEDOnAction(LED3_ID);
				}
			}else if (kNwkGetCurrentStatus() == ENS_LEAVED \
					|| kNwkGetCurrentStatus() == ENS_OFFLINE){
				if(kZclOnOffClusterServerOnOffGet(3)== EOOC_OFF)
					kLedOptTrigger(LED3_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, EOOC_OFF, EOOC_OFF);
				else
					kLedOptTrigger(LED3_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, LED_ON, LED_ON);
			}
			break;
		case RELAY_CHANNEL4_ID:
			if (kNwkGetCurrentStatus() == ENS_ONLINE  || power_on_sync[3] == true \
					|| kGetFactoryTestStatus() == FTS_AGING_4HOU 	\
					|| kGetFactoryTestStatus() == FTS_AGING_DONE 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_RELEASED 	\
					|| kGetFactoryTestStatus() == FTS_WAITING_SECOND_PRESS){
				power_on_sync[3] = false;
				if (status.opt == EZAO_OFF){
					kLEDOffAction(LED4_ID);
				}else if (status.opt == EZAO_ON){
					kLEDOnAction(LED4_ID);
				}
			}else if (kNwkGetCurrentStatus() == ENS_LEAVED \
					|| kNwkGetCurrentStatus() == ENS_OFFLINE){
				if(kZclOnOffClusterServerOnOffGet(4)== EOOC_OFF)
					kLedOptTrigger(LED4_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, EOOC_OFF, EOOC_OFF);
				else
					kLedOptTrigger(LED4_ID, LED_FAST_BLINK_ON_TIME_MS, \
							LED_FAST_BLINK_OFF_TIME_MS, 3, LED_ON, LED_ON);
			}
			break;

		default:
			iKonkeAfSelfPrint("###Erro: Relay Channel is invalid\r\n");
			break;
	}
}
//add by zbw
void kUserPwmActionDoneCallback(unsigned char id, PwmGradientDirectionEnum opt)
{
	switch(id)
	{
		case PWM1_ID:
			kSetLedStatus(LED1_ID);
			break;
		case PWM2_ID:
			kSetLedStatus(LED2_ID);
			break;
		case PWM3_ID:
			kSetLedStatus(LED3_ID);
			break;
		case PWM4_ID:
			kSetLedStatus(LED4_ID);
			break;
		default:
			break;
	}

}
//ota升级失败或入网成功和失败后LED闪烁完成后处理，需要根据不同产品来修改
void kSetLedStatus(LED_ID_ENUM id)
{
	if (id != LED_ALL_ID){
		kPwmClearGradientCounterById(id - 1);
	}else{
		kPwmClearGradientCounterById(PWM1_ID);
		kPwmClearGradientCounterById(PWM2_ID);
		kPwmClearGradientCounterById(PWM3_ID);
		kPwmClearGradientCounterById(PWM4_ID);
	}
	//恢复继电器的LED状态
	if (id == LED_ALL_ID)
	{
		iKonkeAfSelfPrint("##########kSetLedStatus LED_ALL_ID111111111111111111\r\n");
		kLedOptTrigger(LED_ALL_ID, 0, 0, 0, LED_OFF, LED_IGNORE);
		for (uint8_t i = 1; i <= Support_Endpoint_Num; i++){
			if (kLedIsBlinking(GET_LED_ID_BY_ENDPOINT(i, Support_Endpoint_Num)) == false){
				if ((kZclOnOffClusterServerOnOffGet(i) == EOOS_ON)&&(!kGetIndicatorNotDisturbModeFlg())){
					kLEDOnAction(GET_LED_ID_BY_ENDPOINT(i, Support_Endpoint_Num));
				}else {
					kLEDOffAction(GET_LED_ID_BY_ENDPOINT(i, Support_Endpoint_Num));
				}
			}
		}
	}else if (id == LED1_ID || id == LED2_ID || id == LED3_ID || id == LED4_ID){
		iKonkeAfSelfPrint("###kSetLedStatus:%d,%d,%d\r\n",kLedIsBlinking(id),kZclOnOffClusterServerOnOffGet(GET_ENDPOINT(id)),kGetIndicatorNotDisturbModeFlg());
		if (kLedIsBlinking(id) == false){
			if ((kZclOnOffClusterServerOnOffGet(GET_ENDPOINT(id)) == EOOS_ON)&&(!kGetIndicatorNotDisturbModeFlg())){
				kLEDOnAction(id);
			}else {
				kLEDOffAction(id);
			}
		}
	}
}
//固定事件，目前用于心跳上报
s32 kUserScheduleTaskHandler(void *arg)
{
	iKonkeAfSelfPrint("##########kUserScheduleTaskHandlerCallback!!\r\n");
	if (kIsKonkeRemoteGateway() == true){
		kOptTunnelCommonReport(ECA_OPTDATA);
		return HEARTBEAT_TIME_MS;
	}else {
		if (cluster_obj_list[0].cluster != CLUSTER_UNKNOW){
			if (cluster_obj_list[0].cluster  == ZCL_CLUSTER_GEN_POWER_CFG){
			}else {
				if ((g_bIsNotKonkeGatewayFirstReportedFlg )&& kClustePeriodReportCheckIsSet(g_u8CurrentHeartEndpoint)== true){
					//网关设置过report interval，使用SDK的report
				}else {
					kZclClusterSetPermitReportInfo(g_u8CurrentHeartEndpoint, ZCL_CLUSTER_GEN_ON_OFF, true, false ,true, true, NULL, RESET_ENDPOINT);//情景需要加
					kOptTunnelReportingPlagiarizeOriginal(g_u8CurrentHeartEndpoint, ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF);
				}
			}
		}
		g_u8CurrentHeartEndpoint++;
		if (g_u8CurrentHeartEndpoint > Support_Endpoint_Num){
			g_bIsNotKonkeGatewayFirstReportedFlg = true;
			g_u8CurrentHeartEndpoint = 1;
			//repeat overwrite heartbeat report time
			return HEARTBEAT_TIME_MS;
		}else {
			return 1000;
		}
	}

	return HEARTBEAT_TIME_MS;
}
//LED闪烁完成，可以用来恢复继电器的LED状态
void kUserLedActionDoneCallback(unsigned char id)
{
	iKonkeAfSelfPrint("##############kUserLedActionDoneCallback id(%d)nwk(%d)##################\r\n", id, kNwkGetCurrentStatus());
	kSetLedStatus(id);
}
//网关场景控制下发后的属性延时上报处理，可以根据不同场景cluster修改
/*	DESP: recall scene rand delay report Attribute set
 * 	Auth: maozj.20191224.
 * */
void kZclClusterRecallSceneCallback(uint8_t endpoint,  uint16_t cluster, uint8_t command_id, bool reportEnable, bool sceneRecallFlg,\
		bool reportGatewayEnable, bool reportChildDeviceEnable, void *param)
{
	iKonkeAfSelfPrint("####kZclClusterRecallSceneCallback ep(%d)cluster(%d)command_id(%d),reportEnable(%d),sceneRecallFlg(%d)\r\n");
	if((cluster == ZCL_CLUSTER_GEN_ON_OFF)&&(command_id == ZCL_CMD_SCENE_RECALL_SCENE))
	{
		kZclClusterSetPermitReportInfo(endpoint,ZCL_CLUSTER_GEN_ON_OFF,false,true,true,true,NULL,RESET_ENDPOINT);
	}
}

static ev_timer_event_t *kEndpoint1DelayReport = NULL;
static ev_timer_event_t *kEndpoint2DelayReport = NULL;
static ev_timer_event_t *kEndpoint3DelayReport = NULL;
static ev_timer_event_t *kEndpoint4DelayReport = NULL;
static s32 kEndpoint1DelayReportAttrEventHandler(void *arg)
{
	iKonkeAfSelfPrint("######kEndpoint1DelayReportAttrEventHandler\r\n" );
	kZclClusterSetPermitReportInfo(1, ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true, NULL, RESET_ENDPOINT);
	kOptTunnelReportingPlagiarizeOriginal(1, ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF);
	return -1;
}
static s32 kEndpoint2DelayReportAttrEventHandler(void *arg)
{
	iKonkeAfSelfPrint("######kEndpoint2DelayReportAttrEventHandler\r\n" );
	kZclClusterSetPermitReportInfo(2, ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true, NULL, RESET_ENDPOINT);
	kOptTunnelReportingPlagiarizeOriginal(2, ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF);
	return -1;
}
static s32 kEndpoint3DelayReportAttrEventHandler(void *arg)
{
	iKonkeAfSelfPrint("######kEndpoint3DelayReportAttrEventHandler\r\n" );
	kZclClusterSetPermitReportInfo(3, ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true, NULL, RESET_ENDPOINT);
	kOptTunnelReportingPlagiarizeOriginal(3, ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF);
	return -1;
}
static s32 kEndpoint4DelayReportAttrEventHandler(void *arg)
{
	iKonkeAfSelfPrint("######kEndpoint4DelayReportAttrEventHandler\r\n" );
	kZclClusterSetPermitReportInfo(4, ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true, NULL, RESET_ENDPOINT);
	kOptTunnelReportingPlagiarizeOriginal(4, ZCL_CLUSTER_GEN_ON_OFF, ZCL_ATTRID_ONOFF);
	return -1;
}
//网关场景控制下发后的属性延时上报处理，可以根据不同场景cluster修改
/*	DESP: recall scene rand delay report Attribute set
 * 	Auth: maozj.20191224.
 * */
bool kZclClusterReportChangeCallback(uint8_t endpoint, uint16_t clusterId, uint16_t attributeId)
{
	ZclReportTableSt zclReportInfo;
	bool status = kZclClusterGetPermitReportInfo(endpoint,clusterId,&zclReportInfo);
	iKonkeAfSelfPrint("######kZclClusterReportChangeCallback111111111 status(%d)ep(%d)Reportenable(%d)sceneRecall(%d)\r\n",
			status, endpoint, zclReportInfo.reportEnable, zclReportInfo.sceneRecallFlg );
	//不直接上报，随机延时上报
	if (status == true){
		if (zclReportInfo.reportEnable != true && zclReportInfo.sceneRecallFlg == true){
			uint32_t randDelayTimeMS = kGetRandNum(REPORT_ATTR_MIN_RAND_NUM, REPORT_ATTR_MAX_RAND_NUM);
			if (endpoint == 1){
				if(!ev_timer_exist(kEndpoint1DelayReport)) {
					kEndpoint1DelayReport = TL_ZB_TIMER_SCHEDULE(kEndpoint1DelayReportAttrEventHandler, NULL, randDelayTimeMS);
				}
			}else if (endpoint == 2){
				if(!ev_timer_exist(kEndpoint2DelayReport)) {
					kEndpoint2DelayReport = TL_ZB_TIMER_SCHEDULE(kEndpoint2DelayReportAttrEventHandler, NULL, randDelayTimeMS);
				}
			}else if (endpoint == 3){
				if(!ev_timer_exist(kEndpoint3DelayReport)) {
					kEndpoint3DelayReport = TL_ZB_TIMER_SCHEDULE(kEndpoint3DelayReportAttrEventHandler, NULL, randDelayTimeMS);
				}
			}
			else if (endpoint == 4){
				if(!ev_timer_exist(kEndpoint4DelayReport)) {
					kEndpoint4DelayReport = TL_ZB_TIMER_SCHEDULE(kEndpoint4DelayReportAttrEventHandler, NULL, randDelayTimeMS);
				}
			}
			return false;
		}
		else if(!zclReportInfo.reportEnable)
		{
			return false;
		}
	}
	iKonkeAfSelfPrint("reporting disable11111111111111111111111111111111\r\n");

	return true;
}
//Auth: han_frc.20220105.
kk_err_t kUserOODMessageIncoming(uint8_t channel, uint8_t opcode, uint8_t args_in_out[], uint8_t *length_in_out )
{
	if( NULL == args_in_out || NULL == length_in_out ) {
		return KET_ERR_INVALID_POINTER;
	}

	iKonkeAfSelfPrint("OOD-INCOMING: channel(%d), opcode(%x)--\r\n", channel, opcode);
	for(int index = 0; index < *length_in_out; ++index ) {
		iKonkeAfSelfPrint("%x ", args_in_out[index]);
	}
	iKonkeAfSelfPrint("--------------------------------------\r\n");

	switch(opcode) {
	case (0x00): // get the device snap.
	{
		uint8_t command = args_in_out[0];

		if (command == 0x00){
			OnOffStatusEnum  status1= kZclOnOffClusterServerOnOffGet(1);
			OnOffStatusEnum  status2= kZclOnOffClusterServerOnOffGet(2);
			OnOffStatusEnum  status3= kZclOnOffClusterServerOnOffGet(3);
#ifdef FOUR_LIGHT_PANEL
			OnOffStatusEnum  status4= kZclOnOffClusterServerOnOffGet(4);
#endif
			uint8_t channelValue1 = (status1 == EOOS_ON)?1:(status1 == EOOS_UNKNOW?0xFF:0);
			uint8_t channelValue2 = (status2 == EOOS_ON)?1:(status2 == EOOS_UNKNOW?0xFF:0);
			uint8_t channelValue3 = (status3 == EOOS_ON)?1:(status3 == EOOS_UNKNOW?0xFF:0);
#ifdef FOUR_LIGHT_PANEL
			uint8_t channelValue4 = (status4 == EOOS_ON)?1:(status4 == EOOS_UNKNOW?0xFF:0);
#endif
			if (g_ucRelayTotalNum == 1){
				channelValue2 = 0xff; //0xff为私有协议中无效值
				channelValue3 = 0xff;
			}else if (g_ucRelayTotalNum == 2){
				channelValue3 = 0xff;
			}

			args_in_out[0] = 0x00;
			args_in_out[1] = channelValue1;
			args_in_out[2] = channelValue2;
			args_in_out[3] = channelValue3;
#ifndef FOUR_LIGHT_PANEL
			args_in_out[4] = kGetIndicatorNotDisturbModeFlg();
			iKonkeAfSelfPrint("OOOOOOPCODE: 1(%d), 2(%d), 3(%d)\r\n", args_in_out[1], args_in_out[2], args_in_out[3]);
			*length_in_out = 5;
#endif

#ifdef FOUR_LIGHT_PANEL
			args_in_out[4] = channelValue4;
			args_in_out[5] = kGetIndicatorNotDisturbModeFlg();
			iKonkeAfSelfPrint("OOOOOOPCODE: 1(%d), 2(%d), 3(%d)\r\n", args_in_out[1], args_in_out[2], args_in_out[3]);
			*length_in_out = 6;
#endif
		}else if (command == 0x01){
			args_in_out[0] = ERR_NO_NONE;
#ifndef FOUR_LIGHT_PANEL
            OnOffCtrlEnum onoffctrl[3] = {0};
			onoffctrl[0] = args_in_out[1];
			onoffctrl[1] = args_in_out[2];
			onoffctrl[2] = args_in_out[3];
			uint8_t disturb_mode = args_in_out[4];
#endif

#ifdef FOUR_LIGHT_PANEL
			OnOffCtrlEnum onoffctrl[4] = {0};
			onoffctrl[0] = args_in_out[1];
			onoffctrl[1] = args_in_out[2];
			onoffctrl[2] = args_in_out[3];
			onoffctrl[3] = args_in_out[4];
			uint8_t disturb_mode = args_in_out[5];
#endif
			for (uint8_t channelID = 1; channelID <= g_ucRelayTotalNum; channelID++){
				if (kEndpointIsValid(channelID)){ //通道有效
					if (onoffctrl[channelID - 1] != EOOC_OFF && onoffctrl[channelID - 1] != EOOC_ON && onoffctrl[channelID - 1] != EOOC_TOGGLE){
					  args_in_out[0] = ERR_NO_COMMAND_FORMAT;
					  args_in_out[channelID] = 0xff;
					}else{
					  uint8_t status = onoffctrl[channelID - 1];
					  if (onoffctrl[channelID - 1] == EOOC_TOGGLE){ //对翻转需要转换成开/关
						status = kZclOnOffClusterServerOnOffGet(channelID) == EOOC_ON?EOOC_OFF:EOOC_ON;
					  }
					  kZclClusterSetPermitReportInfo(channelID,ZCL_CLUSTER_GEN_ON_OFF,true,false,true,true,NULL,RESET_ENDPOINT);
					  kZclOnOffClusterServerOnOffControl(channelID, status);
					  args_in_out[channelID] = status;
					}
				}else{
					args_in_out[channelID] = 0xff;
				}
			}

			if (disturb_mode != 0x00 && disturb_mode != 0x01){
				args_in_out[0] = ERR_NO_COMMAND_FORMAT;
#ifndef FOUR_LIGHT_PANEL
				args_in_out[4] = 0xff;
#endif

#ifdef FOUR_LIGHT_PANEL
				args_in_out[5] = 0xff;
#endif
			}else{
				//存储勿扰标志
				kSetIndicatorNotDisturbModeFlg(disturb_mode);
				////State Sync////
				if (kLedIsBlinking(LED_ALL_ID) != true)	{
					kSetLedStatus(LED_ALL_ID);
				}
#ifndef FOUR_LIGHT_PANEL
				args_in_out[4] = kGetIndicatorNotDisturbModeFlg();
			}
			*length_in_out = 5;
#endif

#ifdef FOUR_LIGHT_PANEL
				args_in_out[5] = kGetIndicatorNotDisturbModeFlg();
			}
			*length_in_out = 6;
#endif
			iKonkeAfSelfPrint("OOOOOOPCODE: 1(%d), 2(%d), 3(%d)\r\n", args_in_out[1], args_in_out[2], args_in_out[3]);
		}

		break;
	}
	case (0x10): //on/off control
	{
		uint8_t channelID = channel;
		uint8_t onOffStatus = args_in_out[0];
		iKonkeAfSelfPrint("OOOOPCODE ONOFF: channel[%d], onoff[%d]\r\n", channelID, onOffStatus);

		if (kEndpointIsValid(channelID)){ //通道有效
			if (onOffStatus != EOOC_OFF && onOffStatus != EOOC_ON && onOffStatus != EOOC_TOGGLE){
				args_in_out[0] = ERR_NO_COMMAND_FORMAT;
			}else { //下发值正确
				args_in_out[0] = ERR_NO_NONE;
				if (channelID != 0xFF){ //网关单路下发控制
					uint8_t status = onOffStatus;
					if (onOffStatus == EOOC_TOGGLE){ //对翻转需要转换成开/关
						status = kZclOnOffClusterServerOnOffGet(channelID) == EOOC_ON?EOOC_OFF:EOOC_ON;
					}
					kZclClusterSetPermitReportInfo(channelID,ZCL_CLUSTER_GEN_ON_OFF,true,false,true,true,NULL,RESET_ENDPOINT);
					//commandOnOffClusterCallback(status, channelID, true, false);
					kZclOnOffClusterServerOnOffControl(channelID, status);
				}else {  //全部
					if (onOffStatus == EOOC_TOGGLE){//全部通道翻转
						for (uint8_t i = 1; i <= GET_MAX_ENDPOINT(g_ucRelayTotalNum); i++){
							kZclClusterSetPermitReportInfo(i,ZCL_CLUSTER_GEN_ON_OFF,true,false,true,true,NULL,RESET_ENDPOINT);
							kZclOnOffClusterServerOnOffControl(i, EOOC_TOGGLE);
						}
					}else {
						for (uint8_t i = 1; i <= GET_MAX_ENDPOINT(g_ucRelayTotalNum); i++){
							kZclClusterSetPermitReportInfo(i,ZCL_CLUSTER_GEN_ON_OFF,true,false,true,true,NULL,RESET_ENDPOINT);
							kZclOnOffClusterServerOnOffControl(i, onOffStatus);
						}
					}
				}
			}
		}else {
			args_in_out[0] = ERR_NO_COMMAND_FORMAT;
		}

		args_in_out[1] = onOffStatus;//下发命令
		*length_in_out = 2;
		//iKonkeAfSelfPrintln("2.retStatus[%d], channel[%d], onoff[%d]",retStatus, channelID, onOffStatus);
		break;
	}
	case (0xE4):
	{
		uint8_t  u8NetworkSteering_ch = args_in_out[0];
		uint16_t u16NetworkSteering_panid = ((uint16_t)args_in_out[1] << 8) | ((uint16_t)args_in_out[2]);

		kSetNetworkSteeringInfo(u8NetworkSteering_ch, u16NetworkSteering_panid);
		args_in_out[1] = u8NetworkSteering_ch;
		args_in_out[2] = (uint8_t)(u16NetworkSteering_panid >> 8);
		args_in_out[3] = (uint8_t)(u16NetworkSteering_panid);

		args_in_out[0] = ERR_NO_NONE;
		if (kGetFactoryTestStatus() == FTS_NORMAL){
			args_in_out[0] = ERR_NO_COMMAND_FORMAT;
		}
		*length_in_out = 4;

		break;
	}
	case (0xE5):
	{
		kSetAgingTestDone();
		args_in_out[0] = ERR_NO_NONE;
		*length_in_out = 1;
		break;
	}
	case (0xFE):
	{
		//set disturb mode
		uint8_t mode = args_in_out[0];
		if (mode != 0x00 && mode != 0x01){
			args_in_out[0] = ERR_NO_COMMAND_FORMAT;
		}else {
			//存储勿扰标志
			kSetIndicatorNotDisturbModeFlg(mode);
			////State Sync////
			if (kLedIsBlinking(LED_ALL_ID) != true)	{
				kSetLedStatus(LED_ALL_ID);
			}
			args_in_out[0] = ERR_NO_NONE;
		}
		iKonkeAfSelfPrint("Disturb Mode(%d)\r\n", mode);
		args_in_out[1] = mode;
		*length_in_out = 2;
		break;
	}
	case (0xFF):
	{
		int8_t permitJoinTimeS = args_in_out[0]; //unit:s
		iKonkeAfSelfPrint("###Opcode is channel(%d) JoinPermitTime(0x%X)!!\r\n",channel,  permitJoinTimeS);
		//路由协同组网,黄灯闪烁(OTA升级)时不协同组网闪灯
		if (kLedIsBlinking(LED_ALL_ID) != true
				&& permitJoinTimeS != 0
				&& kNwkGetCurrentStatus() != ENS_JOINING){
			iKonkeAfSelfPrint("####LED Blink\r\n");
			kLedOptTrigger(LED_ALL_ID,  LED_SLOW_BLINK_ON_TIME_MS, LED_SLOW_BLINK_OFF_TIME_MS,
					permitJoinTimeS * 1000/(LED_SLOW_BLINK_ON_TIME_MS+LED_SLOW_BLINK_OFF_TIME_MS), LED_ON, LED_OFF);
		}else if (kLedIsBlinking(LED_ALL_ID) == true
				/*&& kGetOTAStatus() == OTA_NORMAL*/
				&& permitJoinTimeS == 0
				&& kNwkGetCurrentStatus() != ENS_JOINING){
			iKonkeAfSelfPrint("####LED Blink over\r\n");
			kLedOptTrigger(LED_ALL_ID, 0, 0, 0, LED_OFF, LED_IGNORE);
//				kLEDOffAction(LED_ALL_ID);
			kSetLedStatus(LED_ALL_ID);
		}
		return KET_NO_RESPONSE;
	}
		default: {
			iKonkeAfSelfPrint("Err: opcode is not exist(%d:%X)!!\r\n", channel, opcode);
			args_in_out[0] = ERR_NO_OPCODE;
			*length_in_out = 1;
			break;
		}
	}

	return KET_OK;
}

//Auth: han_frc.20220105.
static bool kEndpointIsValid(uint8_t endpoint)
{
	bool ret = false;
	if (endpoint == 1){
		ret = true;
	}else if (endpoint == 2 && (g_ucRelayTotalNum == 2 || g_ucRelayTotalNum == 3 || g_ucRelayTotalNum == 4)){
		ret = true;
	}else if (endpoint == 3 && (g_ucRelayTotalNum == 3 || g_ucRelayTotalNum == 4)){
		ret = true;
	}else if (endpoint == 4 && g_ucRelayTotalNum == 4){
		ret = true;
	}else if (endpoint == 0xFF){
		ret = true;
	}
	return ret;
}

static void kLEDOffAction(LED_ID_ENUM led_id)
{
	iKonkeAfSelfPrint("LED_Off_Action LED_ID (%d).\r\n", led_id);
	kLedOptTrigger(led_id, 0, 0, 0, LED_OFF, LED_IGNORE);
	if (kGetIndicatorNotDisturbModeFlg() == false){
		//iKonkeAfSelfPrint("is not NotDisturbMode.\r\n");
		switch (led_id)
		{
			case LED1_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100) );
				break;
			}
			case LED2_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100) );
				break;
			}
			case LED3_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM3_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				break;
			}
			case LED4_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM4_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				break;
			}
			case LED_ALL_ID:
			{
#ifdef SINGLE_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
#endif

#ifdef DUAL_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
#endif

#ifdef THREE_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				kPwmDriverhandler(kPwmGetIndexByID(PWM3_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
#endif

#ifdef FOUR_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				kPwmDriverhandler(kPwmGetIndexByID(PWM3_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
				kPwmDriverhandler(kPwmGetIndexByID(PWM4_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMinLevel * 65535) / 100));
#endif
				break;
			}
			default:
				break;
		}
	}
}

static void kLEDOnAction(LED_ID_ENUM led_id)
{
	iKonkeAfSelfPrint("LED_ON_Action LED_ID (%d).\r\n", led_id);
	kLedOptTrigger(led_id, 0, 0, 0, LED_OFF, LED_IGNORE);
	if (kGetIndicatorNotDisturbModeFlg() == false){
		iKonkeAfSelfPrint("is not NotDisturbMode.\r\n");
		switch (led_id)
		{
			case LED1_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				break;
			}
			case LED2_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				break;
			}
			case LED3_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM3_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				break;
			}
			case LED4_ID:
			{
				kPwmDriverhandler(kPwmGetIndexByID(PWM4_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				break;
			}
			case LED_ALL_ID:
			{
#ifdef SINGLE_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
#endif

#ifdef DUAL_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
#endif

#ifdef THREE_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				kPwmDriverhandler(kPwmGetIndexByID(PWM3_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
#endif

#ifdef FOUR_LIGHT_PANEL
				kPwmDriverhandler(kPwmGetIndexByID(PWM1_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				kPwmDriverhandler(kPwmGetIndexByID(PWM2_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				kPwmDriverhandler(kPwmGetIndexByID(PWM3_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
				kPwmDriverhandler(kPwmGetIndexByID(PWM4_ID), ELP_ANY, (uint16_t)(((uint32_t)g_u8NoDisturbModeMaxLevel * 65535) / 100) );
#endif
				break;
			}
			default:
				break;
		}
	}
}
//芯片上电后延时操作事件，一般处理继电器状态恢复或者禁用SWD口作为普通IO,也用来根据gpio读取电平修改同一类型的不同型号
/*	DESP: system setup delay callback handler, called once.
 * 	Auth: dingmz_frc.20190628.
 * */
s32 kkSystemSetUpEventHandler(void *arg )
{
	bool relayStatusBuffer[Support_Endpoint_Num] = {false, false,false,false};
	nv_sts_t st = zcl_onOffAttr_get();

	for (uint8_t i = 1; i <= Support_Endpoint_Num; i++){
		if(st == NV_SUCC)
		{
			relayStatusBuffer[i-1] = false;
		}
		power_on_sync[i - 1] = true;
		iKonkeAfSelfPrint("###########EP(%d), status(%d)\r\n", i, relayStatusBuffer[i-1]);
		kZclClusterSetPermitReportInfo(i,CLUSTER_ONOFF_ID, false, false, false, false, NULL, RESET_ENDPOINT);
		kZclOnOffClusterServerOnOffSet(i,relayStatusBuffer[i-1]);
		kZclClusterSetPermitReportInfo(i,CLUSTER_ONOFF_ID, false, false, false, false, NULL, RESET_ENDPOINT);

		kRelayChannelOpt(i == 1?RELAY_CHANNEL1_ID:(i == 2?RELAY_CHANNEL2_ID:(i == 3?RELAY_CHANNEL3_ID:RELAY_CHANNEL4_ID)) \
							,relayStatusBuffer[i-1] == false? EZAO_OFF : EZAO_ON);

	}
	//重写attribute
	Update_Local_Attribute_Info();
	#if UART_ENABLE
	kInterPanMoudleInit(kUserInterPanMsgInComingPaser);
	#endif

	addrExt_t addr1;
	zb_getLocalExtAddr(addr1);
	SWAP_EUI64((uint8_t *)addr1);//取反

	iKonkeAfSelfPrint("mac1 :\r\n");
	iKonkeAfSelfPrintBuffer(addr1,8);

	return -1;
}

#if Z30_DEVICE_AGING_ENABLE
//老化的轮询回调函数，一般用于实现老化期间的LED闪烁或继电器翻转，也可以只LED闪烁
void kUserFactorTestPollCallback(FactoryTestStatusEnum status)
{
	//iKonkeAfSelfPrint("##############kUserFactorTestPollCallback status(%d)##################\r\n", status);
	static RelayOptEnum  eRelayStatus = EZAO_OFF;
	switch(status)
	{
		case FTS_NORMAL:
			break;
		case FTS_START:
			break;
		case FTS_AGING_15MIN:
			break;
		case FTS_AGING_4HOU_START:
			//关闭所有的蓝色LED,有可能之前蓝灯闪烁了
			LED_OPT_OFF(LED_ALL_ID);
			LED_OPT_OFF(LED_RADAR_ID);
			if(zb_isDeviceJoinedNwk())
				zb_factoryReset();
			else if(kInterPanGetEnableStatus())
				kInterpanDisable();
			//同步所有的LED和继电器
			for (uint8_t i = 1; i <= Support_Endpoint_Num; i++){
				kRelayChannelOpt(g_ucRelayIdBuff[i-1], EZAO_OFF);
			}
			eRelayStatus = EZAO_ON;
			break;
		case  FTS_AGING_4HOU:
			//翻转继电器，LED也会同步
			eRelayStatus = eRelayStatus == EZAO_ON?EZAO_OFF:EZAO_ON;
			if (eRelayStatus == EZAO_ON){
				LED_OPT_ON(LED_RADAR_ID);
			}else{
				LED_OPT_OFF(LED_RADAR_ID);
			}
			for (uint8_t i = 1; i <= Support_Endpoint_Num; i++){
				kRelayChannelOpt(g_ucRelayIdBuff[i-1], eRelayStatus);
			}
			break;
		case  FTS_AGING_DONE:
			//老化结束后,打开所有的LED和继电器
			LED_OPT_ON(LED_RADAR_ID);
			for (uint8_t i = 1; i <= Support_Endpoint_Num; i++){
				kRelayChannelOpt(g_ucRelayIdBuff[i-1], EZAO_ON);
			}
			eRelayStatus = EZAO_ON;
			//如果有单独系统LED也需要都点亮
//			LED_OPT_ON(LED_SYS_ID);
			break;
		case FTS_FORCE_EXIT:
			iKonkeAfSelfPrint("############## FactoryTestSatus is FTS_FORCE_EXIT\r\n");
			//按键强制退老化，快闪
			kLedOptTrigger(LED_ALL_ID, LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_OFF_TIME_MS, BLINK_DEAD, LED_ON, LED_IGNORE);
			break;
		case FTS_WAITING_RELEASED:
			break;
		case FTS_FIRST_LONG_PRESSED:
			//快闪一次，指示第一次长按有效
			kLedOptTrigger(LED_ALL_ID, LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_OFF_TIME_MS, 1, LED_ON, LED_IGNORE);
			break;
		case FTS_FORCE_REBOOT:
			SYSTEM_RESET();
			break;
		default:
			//iKonkeAfSelfPrint("##############Erro: FactoryTestSatus is not exist\r\n");
			break;
	}
}
#endif

#if Z30_DEVICE_OTA_ENABLE
//如果初始化OTA增加callback这里处理，否则使用ota模块的默认callback,就不在这里
void kOTAMoudleUserCallback(OTAStatusEnum status)
{
#if 1
	static bool flg = false; //防止网关断电后,ota失败后会间隔快闪
	iKonkeAfSelfPrint("##############kOTAMoudleUserCallback status(%d)##################\r\n", status);
	switch(status)
	{
		case OTA_NORMAL:
			break;
		case OTA_START:
			kLedOptTrigger(LED_ALL_ID, 2 * LED_FAST_BLINK_ON_TIME_MS, 14 * LED_FAST_BLINK_ON_TIME_MS,\
					OTA_UPGRADE__CONTINUE_MAX_TIME_MS /(2 * LED_FAST_BLINK_ON_TIME_MS + 14 * LED_FAST_BLINK_ON_TIME_MS), LED_ON, LED_ON);
			kSetOTAStatus(OTA_START);
			flg = false;
			break;
		case OTA_DOWNLOAD_DONE:
		{
		  	kSetOTAStatus(OTA_DOWNLOAD_DONE);
		  	break;
		}
		case OTA_VERITY_SUCCEED:
		{
			//校验成功，记录继电器状态,需要复位后恢复继电器状态
			//常亮5S
			kLedOptTrigger(LED_ALL_ID, 25 * LED_FAST_BLINK_ON_TIME_MS,  LED_FAST_BLINK_ON_TIME_MS, 1, LED_ON, LED_ON);
			kSetOTAStatus(OTA_NORMAL);
			break;
		}
		case OTA_FAILED:
		{
			if (flg != true){
				kLedOptTrigger(LED_ALL_ID, LED_FAST_BLINK_ON_TIME_MS, LED_FAST_BLINK_ON_TIME_MS,\
									LED_FAST_BLINK_CONTINUE_TIME_MS /(LED_FAST_BLINK_ON_TIME_MS + LED_FAST_BLINK_ON_TIME_MS), LED_ON, LED_ON);
				kSetOTAStatus(OTA_NORMAL);
			}
			flg = true;
			break;
		}
		default:
			iKonkeAfSelfPrint("##############Err: OTA status is not exist\r\n");
			break;
	}
#endif
}
#endif

static ev_timer_event_t *kRadarCheckEventControl 	= NULL;
static ev_timer_event_t *kRadarControlLedEvent		= NULL;

s32 kRadarCheckEventHandler(void *arg)
{
	if (kGetFactoryTestStatus() == FTS_AGING_4HOU 	\
		|| kGetFactoryTestStatus() == FTS_AGING_DONE 	\
		|| kGetFactoryTestStatus() == FTS_WAITING_RELEASED 	\
		|| kGetFactoryTestStatus() == FTS_WAITING_SECOND_PRESS){
		return 0;
	}

	static uint8_t Radar_count = 0;
	if (gpio_read(RADAR_PIN)){
		Radar_count ++;
	}else{
		Radar_count = 0;
	}

	if (Radar_count >= 2){
//		iKonkeAfSelfPrint("Radar Action.\r\n");
		Human_body_induction_flag = true;
		Radar_count = 0;
		kRadarLedTragger();
	}
	return 0;
}

s32  kRadarLedEventHandler(void *arg)
{
	if (kGetFactoryTestStatus() == FTS_AGING_4HOU 	\
		|| kGetFactoryTestStatus() == FTS_AGING_DONE 	\
		|| kGetFactoryTestStatus() == FTS_WAITING_RELEASED 	\
		|| kGetFactoryTestStatus() == FTS_WAITING_SECOND_PRESS){
		return 0;
	}

	bool OnOffFlag = false;
#ifdef SINGLE_LIGHT_PANEL
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(1) == EOOS_ON?true:false;
#endif

#ifdef DUAL_LIGHT_PANEL
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(1) == EOOS_ON?true:false;
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(2) == EOOS_ON?true:false;
#endif

#ifdef THREE_LIGHT_PANEL
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(1) == EOOS_ON?true:false;
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(2) == EOOS_ON?true:false;
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(3) == EOOS_ON?true:false;
#endif

#ifdef FOUR_LIGHT_PANEL
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(1) == EOOS_ON?true:false;
	//iKonkeAfSelfPrint("OnOffFlag by endpoint1 : (%d).\r\n",OnOffFlag);
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(2) == EOOS_ON?true:false;
	//iKonkeAfSelfPrint("OnOffFlag by endpoint2 : (%d).\r\n",OnOffFlag);
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(3) == EOOS_ON?true:false;
	//iKonkeAfSelfPrint("OnOffFlag by endpoint3 : (%d).\r\n",OnOffFlag);
	OnOffFlag |= kZclOnOffClusterServerOnOffGet(4) == EOOS_ON?true:false;
	//iKonkeAfSelfPrint("OnOffFlag by endpoint4 : (%d).\r\n",OnOffFlag);
#endif

	if (OnOffFlag == true){
		kLedOptTrigger(LED_RADAR_ID, 0, 0, 0, LED_ON, LED_IGNORE);
		Human_body_induction_flag = false;
	}else if (Human_body_induction_flag == true){
		kLedOptTrigger(LED_RADAR_ID, RADAR_ON_TIME_MS, 0, 1, LED_ON, LED_OFF);
		Human_body_induction_flag = false;
	}else{
		kLedOptTrigger(LED_RADAR_ID, RADAR_ON_TIME_MS, 0, 1, LED_ON, LED_OFF);
	}
	return -1;
}
void kRadarDetectInit(void)
{
	if(!ev_timer_exist(kRadarCheckEventControl)) {
		kRadarCheckEventControl = TL_ZB_TIMER_SCHEDULE(kRadarCheckEventHandler, NULL, 100);
	}
	GPIO_INPUT_SET(RADAR_PIN,PM_PIN_UP_DOWN_FLOAT);
}
void kRadarLedTragger(void)
{
	if(!ev_timer_exist(kRadarControlLedEvent)){
		TL_ZB_TIMER_CANCEL(&kRadarControlLedEvent);
	}
	kRadarControlLedEvent = TL_ZB_TIMER_SCHEDULE(kRadarLedEventHandler, NULL, 1);

}

#if UART_ENABLE
uint8_t uart_send(void)
{
	UMsgNodeSt MsgNode;
	uint8_t i = 0;
	memset(&MsgNode,0,sizeof(UMsgNodeSt));
	MsgNode.buffer[i++]	= 0xAA;
	MsgNode.buffer[i++] = 0X55;
	MsgNode.buffer[i++]	= 0X05;
	MsgNode.buffer[i++]	= 0x01;
	MsgNode.buffer[i++]  = 0X02;
	MsgNode.buffer[i++]	= 0X03;
	MsgNode.buffer[i++]	= 0X04;
	MsgNode.buffer[i++]	= 0X05;


	uint16_t crc = check_sum(&MsgNode.buffer[0], MsgNode.buffer[2]+3);
	MsgNode.buffer[i++] = crc>>8;
	MsgNode.buffer[i++] = crc;
	MsgNode.length = i;

	// setting for matcher content.

	MsgNode.matcher[0] = 0XAA;
	MsgNode.matcher[0] = 0X55;
	MsgNode.matcher_offset = 4;
	MsgNode.matcher_n = 2;

	MsgNode.sent_try = 3;

	return kUartMsgSent(&MsgNode);
}
void UartMsgProcessHandle(UMsgNodeSt *pMsgNode )
{
	uint16_t opcode;
	uint16_t frameLenth = 0;
	uint8_t *args_in;
	uint8_t reply_control_field;
	DataField_st send_buf;

	if( NULL == pMsgNode ) {
		return ;
	}

#if 1 // Just for debug
	iKonkeAfSelfPrint("\r\n-- RTT MSG INCOMING[%d]:\r\n", pMsgNode->length);

	iKonkeAfSelfPrintBuffer(pMsgNode->buffer, pMsgNode->length);
	iKonkeAfSelfPrint("\r\n--------------------\r\n");
#endif

	// check SOF
	if ((pMsgNode->buffer[0] != 0xAA) || (pMsgNode->buffer[1] != 0x55)) {
		return ;
	}
	frameLenth = UINT16_HL(pMsgNode->buffer[2], pMsgNode->buffer[3]);

	// check for parsable packets
	if( pMsgNode->length < 10 /* Minimum Packet Length */ ) {
		iKonkeAfSelfPrint("Err: Unparsable Packets!!\r\n");
		return ;
	}

	opcode = ((uint16_t)pMsgNode->buffer[9] << 8) |  (uint16_t)(pMsgNode->buffer[10]);
	args_in = &pMsgNode->buffer[8];
	send_buf.seq = UINT16_HL(pMsgNode->buffer[5],pMsgNode->buffer[6] );
	send_buf.u8ChannelID = args_in[0];
	send_buf.u16Opcode = opcode;
	iKonkeAfSelfPrint("opcode(%d)\r\n", opcode);
	reply_control_field = Z_TO_H_NO_ACK;
	switch(opcode){
		case UART_MSG_READ_DEVICE_SNAP_OPCODE:
		case UART_MSG_JOIN_NWK_REQUEST_OPCODE:
		case UART_MSG_LEAVE_NWK_REQUEST_OPCODE:
		case UART_MSG_QUERY_NWK_STATUS_REQUEST_OPCODE:
		case UART_MSG_NWK_STATUS_NOTIFY_OPCODE:
		case UART_MSG_READ_ATTRIBUTE_REQUEST_OPCODE:
		case UART_MSG_WRITE_ATTRIBUTE_REQUEST_OPCODE:
		case UART_MSG_WRITE_CMEI_CODE_OPCODE:
		case UART_MSG_READ_CMEI_CODE_OPCODE:
		case UART_MSG_WRITE_ISN_CODE_OPCODE:
		case UART_MSG_READ_ISN_CODE_OPCODE:
		case UART_MSG_ZCL_COMMAND_REQUEST_OPCODE:
		case UART_MSG_BIND_REQUEST_OPCODE:
		case UART_MSG_WRITE_INSTALL_CODE_OPCODE:
		case UART_MSG_READ_INSTALL_CODE_OPCODE:
		case UART_MSG_WRITE_MAC_CODE_OPCODE:
		case UART_MSG_READ_MAC_CODE_OPCODE:
		case UART_MSG_WRITE_MOUDLE_ID_OPCODE:
		case UART_MSG_READ_MOUDLE_ID_OPCODE:
		case UART_MSG_READ_DEV_RSSI_OPCODE:
		case UART_MSG_WRITE_AGING_TIME_OPCODE:
		case UART_MSG_READ_AGING_TIME_OPCODE:
		case UART_MSG_WRITE_INTERPAN_PARA_OPCODE:
		case UART_MSG_READ_INTERPAN_PARA_OPCODE:
			kCmdGeneralMsgPaser(pMsgNode, ECOM_PORT_UART, &send_buf);
			break;
		case UART_MSG_QUERY_INFO_OPCODE:
		case UART_MSG_QUERY_DEVICE_VERSION_OPCODE:
		case UART_MSG_QUERY_DEVICE_INFO_OPCODE:
		case UART_MSG_CONFIG_DEVICE_SLEEP_OPCODE:
		case UART_MSG_EXIT_FACTORY_TEST_OPCODE:
		case UART_MSG_QUERY_SWITCH_ONOFF_OPCODE:
		case UART_MSG_QUERY_FACTORY_INFO_OPCODE:
		case UART_MSG_ENTER_FACTORY_TEST_OPCODE:
		case UART_MSG_ONOFF_SWITCH_OPCODE:
        case UART_MSG_QUERY_FACTORY_STATE_OPCODE:
        case UART_MSG_LED_GROUP_CONTROL_OPCODE:
			kkFactoryMsgInComingPaser(pMsgNode, ECOM_PORT_UART, &send_buf);
			break;

		default:
			send_buf.u8ARG[0] = ERR_NOT_EXIST;
			send_buf.u8ArgLen = 1;
			reply_control_field = Z_TO_H_NO_ACK;
			break;
	}
	reply_control_field = Z_TO_H_NO_ACK;
	kCmdMsgDataSentByPort(reply_control_field, send_buf, false, ECOM_PORT_UART);
}
/*  DESP: rtt command message incoming and process interface.
 *   Auth: kkk.20210222.
 * */
void kUserInterPanMsgInComingPaser(UMsgNodeSt *pMsgNode)
{
	uint16_t opcode;
	uint16_t frameLenth = 0;
	uint16_t crc16DataIn = 0;
	uint16_t crc16Value = 0;
	uint8_t *args_in;
	uint8_t reply_control_field;
	DataField_st send_buf;

	if( NULL == pMsgNode ) {
		return ;
	}

#if 0 // Just for debug
	iKonkeAfSelfPrint("\r\n-- InterPan MSG INCOMING[%d]:\r\n", pMsgNode->length);
	iKonkeAfSelfPrintBuffer(pMsgNode->buffer, pMsgNode->length);
	iKonkeAfSelfPrint("\r\n--------------------\r\n");
#endif

	// check SOF
	if ((pMsgNode->buffer[0] != 0xAA) || (pMsgNode->buffer[1] != 0x55)) {
		return ;
	}

	frameLenth = UINT16_HL(pMsgNode->buffer[2], pMsgNode->buffer[3]);
	// check CRC16
	crc16Value = kCmdGetMsgCrc16Value(&pMsgNode->buffer[4], frameLenth);
	crc16DataIn = UINT16_HL(pMsgNode->buffer[pMsgNode->length - 2], pMsgNode->buffer[pMsgNode->length - 1]);

	if (crc16Value != crc16DataIn) {
		iKonkeAfSelfPrint("Err: CRC(%d)(%d)\r\n", crc16Value, crc16DataIn);
		return ;
	}

	// check for parsable packets
	if( pMsgNode->length < 10 /* Minimum Packet Length */ ) {
		iKonkeAfSelfPrint("Err: Unparsable Packets!!\r\n");
		return ;
	}

	opcode = ((uint16_t)pMsgNode->buffer[9] << 8) |  (uint16_t)(pMsgNode->buffer[10]);
	args_in = &pMsgNode->buffer[8];
	send_buf.seq = UINT16_HL(pMsgNode->buffer[5],pMsgNode->buffer[6] );
	send_buf.u8ChannelID = args_in[0];
	send_buf.u16Opcode = opcode;

	iKonkeAfSelfPrint("opcode(%d)\r\n", opcode);
	  switch(opcode){
		case UART_MSG_READ_DEVICE_SNAP_OPCODE:
		case UART_MSG_JOIN_NWK_REQUEST_OPCODE:
		case UART_MSG_LEAVE_NWK_REQUEST_OPCODE:
		case UART_MSG_QUERY_NWK_STATUS_REQUEST_OPCODE:
		case UART_MSG_NWK_STATUS_NOTIFY_OPCODE:
		case UART_MSG_READ_ATTRIBUTE_REQUEST_OPCODE:
		case UART_MSG_WRITE_ATTRIBUTE_REQUEST_OPCODE:
		case UART_MSG_WRITE_CMEI_CODE_OPCODE:
		case UART_MSG_READ_CMEI_CODE_OPCODE:
		case UART_MSG_WRITE_ISN_CODE_OPCODE:
		case UART_MSG_READ_ISN_CODE_OPCODE:
		case UART_MSG_ZCL_COMMAND_REQUEST_OPCODE:
		case UART_MSG_BIND_REQUEST_OPCODE:
		case UART_MSG_WRITE_INSTALL_CODE_OPCODE:
		case UART_MSG_READ_INSTALL_CODE_OPCODE:
		case UART_MSG_WRITE_MAC_CODE_OPCODE:
		case UART_MSG_READ_MAC_CODE_OPCODE:
		case UART_MSG_WRITE_MOUDLE_ID_OPCODE:
		case UART_MSG_READ_MOUDLE_ID_OPCODE:
		case UART_MSG_READ_DEV_RSSI_OPCODE:
		case UART_MSG_WRITE_AGING_TIME_OPCODE:
		case UART_MSG_READ_AGING_TIME_OPCODE:
		case UART_MSG_WRITE_INTERPAN_PARA_OPCODE:
		case UART_MSG_READ_INTERPAN_PARA_OPCODE:
		  kCmdGeneralMsgPaser(pMsgNode, ECOM_PORT_INTERPAN, &send_buf);
		  break;
		case UART_MSG_QUERY_INFO_OPCODE:
		case UART_MSG_QUERY_DEVICE_VERSION_OPCODE:
		case UART_MSG_QUERY_DEVICE_INFO_OPCODE:
		case UART_MSG_CONFIG_DEVICE_SLEEP_OPCODE:
		case UART_MSG_EXIT_FACTORY_TEST_OPCODE:
		case UART_MSG_QUERY_FACTORY_INFO_OPCODE:
		case UART_MSG_QUERY_SWITCH_ONOFF_OPCODE:
		case UART_MSG_ENTER_FACTORY_TEST_OPCODE:
		case UART_MSG_ONOFF_SWITCH_OPCODE:
		case UART_MSG_QUERY_FACTORY_STATE_OPCODE:
		case UART_MSG_LED_GROUP_CONTROL_OPCODE:
		  kkFactoryMsgInComingPaser(pMsgNode, ECOM_PORT_INTERPAN, &send_buf);
		  break;

		default:
			send_buf.u8ARG[0] = ERR_NOT_EXIST;
			send_buf.u8ArgLen = 1;
			reply_control_field = Z_TO_H_NO_ACK;
		  break;
	  }

	  reply_control_field = Z_TO_H_NO_ACK;
	  kCmdMsgDataSentByPort(reply_control_field, send_buf, false, ECOM_PORT_INTERPAN);
}
uint16_t check_sum( uint8_t* msg, uint8_t len)
{
	uint16_t crc = 0xFFFF;
	uint16_t i, j = 0;

    for (i = 0; i < len; i++)
    {
        for (j = 0; j < 8; j++)
        {
        	uint8_t c15 = (uint8_t)((crc >> 15 & 1) == 1);
        	uint8_t bit = (uint8_t)((msg[i] >> (7 - j) & 1) == 1);

            crc <<= 1;

            if (c15 ^ bit)
            {
                crc ^= 0x1021;
            }
        }
    }
    return crc;
}
bool MsgCRC16(uint8_t *pdat, int length )
{
	uint16_t crc_data = 0;
	uint8_t  CRC_H = 0;
	uint8_t  CRC_L = 0;

	if((NULL == pdat) || (length < 9)){
		return false;
	}
	crc_data = check_sum(&pdat[4], pdat[3]);
	CRC_H = (crc_data>>8) & 0xff;
	CRC_L = crc_data & 0xff;
	//iKonkeAfSelfPrint("\r\nMsgCRC16,%d,%d\r\n",CRC_H,CRC_L);
	if((pdat[length - 1] == CRC_L) && (pdat[length - 2]== CRC_H))
	{
		return true;
	}

	return false;
}
#endif
