#include "app/framework/include/af.h"
#include "app/util/zigbee-framework/zigbee-device-common.h"
#include "stdio.h"
#include "stdbool.h"

#include "ikk-debug.h"
#include "ikk-module-def.h"
#include "ikk-common-utils.h"
#include "ikk-opt-tunnel.h"
#include "ikk-command.h"
#include "ikk-network.h"



// command incoming global manager.
CommandIncomingMagSt g_stCmdIncomingMager = { 0 };
// command outgoing global manager.
CommandOutgoingMagSt g_stCmdOutgoingMager = { 0 };

// supported commands list
CommandDefSt g_stCommandsDef[] = STATIC_COMMAND_DEF;

// command images cache list for ack reply detection
CommandImageNodeSt g_stCmdImageList[CMDIMAGE_LIST_DEPTH] = { 0 };

EmberEventControl kCmdCommandImageHandleEventControl;

// link layer ack enable switch. when disable, the downlink command will no longer check errors and confirm
// , and the uplink command will no longer be re-send!!!
static bool g_bLinkAckEnableFlag = true;
static bool g_bLinkCRCVerifyEnableFlag = true;

// EXTERN FUNCTIONS DECLARE
void emberAfGetEui64(EmberEUI64 returnEui64);
EmberNodeId emberAfGetNodeId(void);
EmberStatus emberAfGetNetworkParameters(EmberNodeType* nodeType, EmberNetworkParameters* parameters);
EmberStatus emberAfPluginNetworkCreatorNetworkForm(bool centralizedNetwork, EmberPanId panId, int8_t radioTxPower, uint8_t channel);
void removeServer(uint8_t* ieeeAddress);
uint8_t emberAfGetChildTableSize(void);
void networkLeaveCommand(void);
void NWK_ClearRssi(void);
EmberStatus emberLeaveRequest(EmberNodeId target, EmberEUI64 deviceAddress, uint8_t leaveRequestFlags, EmberApsOption options);
//void emAfClearServers(void);
EmberStatus emberAfGetChildData(uint8_t index, EmberChildData *childData);
//EmberStatus emberAfPluginNetworkCreatorSecurityOpenNetwork(void);
//EmberStatus emberAfPluginNetworkCreatorSecurityCloseNetwork(void);
//EmberStatus emberAfPluginNetworkCreatorStart(bool centralizedNetwork);
void emAfApsFrameClusterIdSetup(uint16_t clusterId);
EmberStatus emberAfSendUnicast(EmberOutgoingMessageType type, uint16_t indexOrDestination, EmberApsFrame *apsFrame,
                               uint16_t messageLength, uint8_t *message);
bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, const EmberAfOtaImageId* id);
//bool kkOtaImageBlockWrite(int offset_in, char *pdata );


// Obtain the next sequence number to be used in ZDP message, application layer!!!
#define ZDPAPP_NEXT_SEQ() ((emberGetLastAppZigDevRequestSequence() + 1) & 0X7F/*SAME TO APPLICATION_ZDO_SEQUENCE_MASK*/)
// Obtain the next sequence number to be used in ZDP message, stack layer!!!
#define ZDPSTK_NEXT_SEQ() ((emberGetLastStackZigDevRequestSequence() == 0XFF)?(0X80):(emberGetLastStackZigDevRequestSequence() + 1))
// Obtain the next sequence number to be used in ZCL message, application layer!!!
#define ZCLAPP_NEXT_SEQ() ((emberAfGetLastSequenceNumber() + 1) & 0X7F/*SAME TO EMBER_AF_ZCL_SEQUENCE_MASK*/)

uint16_t kCmdGetMsgCrc16Value( 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++)
        {
            //强制转换 ADD BY YWQ
            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;
            }
        }
    }

//    iKonkeAfSelfPrint("---create_crc16_data(0x%2x)----\r\n",crc);
//	iKonkeAfSelfPrint("--------------------\r\n");
    return crc;
}



uint8_t kCmdGetMsgSum(uint8_t *pdat, int length )
{
	if( NULL == pdat ) return false;

	uint8_t crc_value = 0;

	for(int index = 0; index < length; ++index ) {
		crc_value += pdat[index];
	}

	return (crc_value);
}

bool kCmdCheckMsgCRC16(uint8_t *pdat, int length )
{
	if((NULL == pdat) || (length < 8)) {
		return false;
	}

//	iKonkeAfSelfPrint("-- CRC[%d]:(0x%0x)\r\n", length,pdat[length - 1]);

	return (kCmdGetMsgCrc16Value(pdat + 4, length - 6) == (uint16_t)(((uint16_t)pdat[length - 2] << 8) | (uint16_t)pdat[length - 1]));
}

kk_err_t kCommandMsgSent(DataField_st *buffer)
{
	UMsgNodeSt uMsgNode;

//	static uint16_t seq = 0x00;
//	iKonkeAfSelfPrint("-------------- 11: %d -------\r\n", halCommonGetInt32uMillisecondTick());
	uint8_t length = 0;

	uMsgNode.buffer[length++]  = 0XAA;
	uMsgNode.buffer[length++]  = 0X55;

	uMsgNode.buffer[length++]  = 0x00;//数据长度
	uMsgNode.buffer[length++]  = 0x00;	//数据长度
	uMsgNode.buffer[length++]  = 0x20;
//	seq++;
	uMsgNode.buffer[length++]  = (uint8_t)(buffer->seq >> 8);
	uMsgNode.buffer[length++]  = (uint8_t)buffer->seq;
	uMsgNode.buffer[length++]  = buffer->u8Datalen;
	uMsgNode.buffer[length++]  = buffer->u8ChannelID;
	uMsgNode.buffer[length++]  = (uint8_t)(buffer->u16Opcode >> 8);
	uMsgNode.buffer[length++]  = (uint8_t)buffer->u16Opcode;
	memcpy(&uMsgNode.buffer[length],buffer->u8ARG,buffer->u8Datalen - 3);
	length = length + buffer->u8Datalen - 3;
	uMsgNode.buffer[2] = (uint8_t)((length - 4) >> 8);
	uMsgNode.buffer[3] = (uint8_t)(length - 4);
	uint16_t crc = kCmdGetMsgCrc16Value(&uMsgNode.buffer[4],length - 4);

	uMsgNode.buffer[length++] = (uint8_t)(crc >> 8);
	uMsgNode.buffer[length++] = (uint8_t)(crc);

	uMsgNode.length = length;

	// setting for matcher content.
//	uMsgNode.matcher[0] = cmd_type;
//	uMsgNode.matcher_offset = CMD_OFFSET;
//	uMsgNode.matcher_n = 1;
//	uMsgNode.sent_try = 0;
//	uMsgNode.bRspNeedtoDispatch = false;

	kk_err_t err = kUartMsgSent(&uMsgNode, 200);
	return err;
}
#if 1
uint8_t kCmdMsgDataSent(uint8_t ucControl_Field ,DataField_st data, bool isGetResult)
{
	UMsgNodeSt uMsgNode;

//	static uint16_t seq = 0x00;
//	iKonkeAfSelfPrint("-------------- 11: %d -------\r\n", halCommonGetInt32uMillisecondTick());
	uint8_t length = 0;

	uMsgNode.buffer[length++]  = 0XAA; //msg header
	uMsgNode.buffer[length++]  = 0X55; //msg header

	uMsgNode.buffer[length++]  = 0x00;//数据长度
	uMsgNode.buffer[length++]  = 0x00;	//数据长度
	uMsgNode.buffer[length++]  = ucControl_Field;
//	seq++;
	uMsgNode.buffer[length++]  = (uint8_t)(data.seq >> 8);
	uMsgNode.buffer[length++]  = (uint8_t)data.seq;
	uMsgNode.buffer[length++]  = data.u8Datalen;
	uMsgNode.buffer[length++]  = data.u8ChannelID;
	uMsgNode.buffer[length++]  = (uint8_t)(data.u16Opcode >> 8);
	uMsgNode.buffer[length++]  = (uint8_t)data.u16Opcode;
	memcpy(&uMsgNode.buffer[length], data.u8ARG, data.u8Datalen - 3);
	length = length + data.u8Datalen - 3;
	uMsgNode.buffer[2] = (uint8_t)((length - 4) >> 8);
	uMsgNode.buffer[3] = (uint8_t)(length - 4);
	uint16_t crc = kCmdGetMsgCrc16Value(&uMsgNode.buffer[4], length - 4);

	uMsgNode.buffer[length++] = (uint8_t)(crc >> 8);
	uMsgNode.buffer[length++] = (uint8_t)(crc);

	uMsgNode.length = length;

	// setting for matcher content.

	uMsgNode.matcher[0] = uMsgNode.buffer[2];						//seq
	uMsgNode.matcher[1] = uMsgNode.buffer[3];
	uMsgNode.matcher_offset = 2;
	uMsgNode.matcher_n = 2;
	//zigbee send to host ack
	if (ucControl_Field == Z_TO_H_NO_ACK) {
		uMsgNode.sent_try = 0;
	}else if (ucControl_Field == Z_TO_H_WITH_ACK) {
		//zigbee send to host notify or control
		uMsgNode.sent_try = 1;
	}

	if(isGetResult)
		uMsgNode.ack = uMsgNode.buffer;
	else
		uMsgNode.ack = NULL;
	uMsgNode.ack_length = 0;
	return kUartMsgSent(&uMsgNode, 300);
}

#endif
/*	DESP: Obtain the information of child nodes according to the short address.
 * 	Auth: dingmz_frc.20191019.
 * */
void kCmdGetChildDataByNodeID(uint16_t node_id, EmberChildData *childData )
{
	uint8_t index = 0, size = emberAfGetChildTableSize();

	childData->type = EMBER_UNKNOWN_DEVICE;

	for(index = 0; index < size; ++ index ) {
		EmberStatus status = emberAfGetChildData(index, childData);

		if( status == EMBER_SUCCESS ) {
			if( childData->id == node_id ) {
				break;
			}
		}
	}

	if( childData->type == EMBER_UNKNOWN_DEVICE ) {
		memset(childData->eui64, 0, EUI64_SIZE);
		childData->id = 0;
	}
}

/*	DESP: Obtain the information of child nodes according to the IEEE address.
 * 	Auth: dingmz_frc.20191019.
 * */
void kCmdGetChildDataByIEEE(EmberEUI64 ieee, EmberChildData *childData )
{
	uint8_t index = 0, size = emberAfGetChildTableSize();

	childData->type = EMBER_UNKNOWN_DEVICE;

	for(index = 0; index < size; ++ index ) {
		EmberStatus status = emberAfGetChildData(index, childData);

		if( status == EMBER_SUCCESS ) {
			if( memcmp(childData->eui64, ieee, EUI64_SIZE) == 0 ) {
				break;
			}
		}
	}

	if( childData->type == EMBER_UNKNOWN_DEVICE ) {
		memset(childData->eui64, 0, EUI64_SIZE);
		childData->id = 0;
	}
}
#if 1
/*	DESP: Custom private command processing interface.
 * 	Auth: maozj.20200723.
 * */
void kCmdGeneralMsgHanderCallback(UMsgNodeSt *pMsgNode )
{
	UMsgNodeSt uMsgNode = {0};
	uint16_t length;
	uint8_t control_field;
//	uint16_t seq;
	DataField_st data;
	DataField_st send_buf;

	if( NULL == pMsgNode ) {
		return ;
	}

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

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

	length = ((uint16_t)pMsgNode->buffer[2] << 8) |  (uint16_t)(pMsgNode->buffer[3]);
	control_field = pMsgNode->buffer[4];

	data.seq = ((uint16_t)pMsgNode->buffer[5] << 8) |  (uint16_t)(pMsgNode->buffer[6]);

	data.u8Datalen = pMsgNode->buffer[7];
	data.u8ChannelID = pMsgNode->buffer[8];
	data.u16Opcode = ((uint16_t)pMsgNode->buffer[9] << 8) |  (uint16_t)(pMsgNode->buffer[10]);
	memcpy(data.u8ARG,&pMsgNode->buffer[11],data.u8Datalen - 3);

	send_buf.seq = data.seq;
	send_buf.u8ChannelID = data.u8ChannelID;
	send_buf.u16Opcode = data.u16Opcode;

	switch(data.u16Opcode) {
//		case (ECMD_NETWORK_UP_REQ):
//		{
//			uint8_t opttype = (uint8_t )kUtilsOct2Value(g_stCmdIncomingMager.param[0], 2);
//			uint16_t panid  = (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[1], 4);
//			int channel = atoi(g_stCmdIncomingMager.param[2]);
//			int power   = atoi(g_stCmdIncomingMager.param[3]);
//			EmberStatus status = EMBER_SUCCESS;
//
//			if( opttype == 0X01 ) { // force network creation based on specified parameters!!!
//
//				if( panid == 0XFFFF ) {
//					panid = NETWORK_UP_PAN_DEFAULT;
//				}
//
//				if( channel < 11 || channel > 26 ) {
//					channel = NETWORK_UP_CHANNEL_DEFAULT;
//				}
//
//				if( power < -10 || power > 20 ) {
//					power = NETWORK_UP_POWER_DEFAULT;
//				}
//
//				iKonkeAfSelfPrint("NetworUp: pan(%2x), channel(%d), power(%d)\r\n", panid, channel, power);
//
//				status = emberAfPluginNetworkCreatorNetworkForm(true, panid, power, channel);
//				if( status == EMBER_SUCCESS ) {
//					kk_err_t err = kCmdOutgoingCommandSetUp(ECMD_NETWORK_UP_ACK, NODE_ID_LOCAL, ENDPOINT_UNKNOW, CLUSTER_UNKNOW, CLUSTER_CMD_UNKNOW, TRANSMIT_SEQ_UNKNOW);
//					if( err == KET_OK ) {
//						kCmdOutgoingCommandPutInU8int(0x00, true);
//						kCmdOutgoingCommandPutInU16int(panid, true);
//						kCmdOutgoingCommandPutInInt(channel, true);
//						kCmdOutgoingCommandPutInInt(power, true);
//						kCmdOutgoingCommandSent();
//					}
//				}
//			}else { // Automatically create a network
//				status = emberAfPluginNetworkCreatorStart(true);
//				if( status == EMBER_SUCCESS ) {
//					err = KET_ERR_OPRATE_IN_PROGRESS;
//				}
//			}
//
//			if( status != EMBER_SUCCESS ) {
//				EmberNodeType nodeTypeResult = 0xFF;
//				EmberNetworkParameters networkParams = { 0 };
//
//				emberAfGetNetworkParameters(&nodeTypeResult, &networkParams);
//
//				err = kCmdOutgoingCommandSetUp(ECMD_NETWORK_UP_ACK, NODE_ID_LOCAL, ENDPOINT_UNKNOW, CLUSTER_UNKNOW, CLUSTER_CMD_UNKNOW, TRANSMIT_SEQ_UNKNOW);
//				if( err == KET_OK ) {
//					kCmdOutgoingCommandPutInU8int(status, true);
//					kCmdOutgoingCommandPutInU16int(networkParams.panId, true);
//					kCmdOutgoingCommandPutInInt(networkParams.radioChannel, true);
//					kCmdOutgoingCommandPutInInt(networkParams.radioTxPower, true);
//					kCmdOutgoingCommandSent();
//				}
//			}
//
//			break;
//		}
		case (UART_MSG_LEAVE_NWK_REQUEST_OPCODE):
		{
			if( emberAfNetworkState() == EMBER_JOINED_NETWORK || emberAfNetworkState() == EMBER_JOINED_NETWORK_NO_PARENT) {
				send_buf.u8ARG[0] = ERR_OK;
				kNwkFactoryReset(false);
			}else {
				send_buf.u8ARG[0] = ERR_NOT_EXPECTED;
			}
			send_buf.u8Datalen = 4;
			kCmdMsgDataSent(Z_TO_H_NO_ACK, send_buf, false);
			break;
		}
		case (UART_MSG_QUERY_NWK_STATUS_REQUEST_OPCODE):
			send_buf.u8ARG[0] = ERR_OK;
			send_buf.u8ARG[1] = kNwkGetCurrentStatus();
			send_buf.u8Datalen = 5;
			//kkUartMsgSent(&send_buf);
			kCmdMsgDataSent(Z_TO_H_NO_ACK, send_buf, false);
			break;
#if 0
		case (ECMD_LEAVE_REQ):
		{
			EmberEUI64 DestEui64 = { 0, 0, 0, 0, 0, 0, 0, 0 };
			EmberStatus status = EMBER_SUCCESS;
			uint8_t zdo_seq = ZDPAPP_NEXT_SEQ();

			uint16_t parent_id = (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[0], 4);

			for(int index = 0; index < 8; index++) {
				DestEui64[7 - index] = (uint8_t)kUtilsOct2Value((char *)(g_stCmdIncomingMager.param[1] + index * 2), 2);
			}

			iKonkeAfSelfPrint("Leave REQ: parent_id(%2X), dest_ieee(%X%X%X%X%X%X%X%X)\r\n", parent_id
				, DestEui64[7], DestEui64[6], DestEui64[5], DestEui64[4]
				, DestEui64[3], DestEui64[2], DestEui64[1], DestEui64[0]);

			uint8_t options = EMBER_ZIGBEE_LEAVE_WITHOUT_REJOIN;

			// remove the IAS device record
			//removeServer(DestEui64);
			// send device leave request
			status = emberLeaveRequest(parent_id, DestEui64, options, EMBER_APS_OPTION_RETRY);

			err = kCmdOutgoingCommandSetUp(ECMD_LEAVE_ACK, parent_id, ENDPOINT_UNKNOW, CLUSTER_UNKNOW, CLUSTER_CMD_UNKNOW, zdo_seq);
			if( err == KET_OK ) {
				kCmdOutgoingCommandPutInU8int(status, true);
				kCmdOutgoingCommandSent();
			}

			break;
		}
#endif
#if 0
		case (ECMD_BIND_REQ):
		{
			EmberEUI64 SrcEui64 = { 0 }, DestEui64 = { 0 };
			uint8_t zdp_seq = ZDPAPP_NEXT_SEQ();

			uint16_t target = 0;
			uint16_t sourceEndpoint = 1;
			uint16_t destinationEndpoint = 1;

			for(int index = 0; index < 8; index++) {
				SrcEui64[7 - index]  = 0;
			}
			for(int index = 0; index < 8; index++) {
				DestEui64[7 - index] = 0;
			}

			uint16_t clusterId = 0;

			EmberStatus status = emberBindRequest(target, SrcEui64, sourceEndpoint, clusterId, UNICAST_BINDING,
				DestEui64, 0, destinationEndpoint, EMBER_AF_DEFAULT_APS_OPTIONS);



			break;
		}
#endif
#if 0
		case (ECMD_CLUSTER_CMD_REQ):
		{
			uint16_t target   = 0;
			uint8_t des_ep 	  = 0;
			uint16_t cluster  = 0;
			uint16_t mfg_code = 0;
			uint8_t direction = 0;
			uint8_t cmd_type  = 0;
			uint8_t cls_cmd_id= 0;
			uint8_t delivery  = 0;
			uint8_t zcl_seq   = emberAfNextSequence();

			uint8_t tmpZclBuffer[128] = { 0 }, tmpLength = 1;

			tmpZclBuffer[0] = cmd_type;

			// Manufacturer specific
			if( mfg_code > 0 ) {
				tmpZclBuffer[0] |= BIT(2);
				tmpZclBuffer[tmpLength++] = (mfg_code >> 0) & 0xff;
				tmpZclBuffer[tmpLength++] = (mfg_code >> 8) & 0xff;
			}

			// Direction
			if( direction ) {
				tmpZclBuffer[0] |= BIT(3);
			}

			tmpZclBuffer[tmpLength++] = zcl_seq;
			tmpZclBuffer[tmpLength++] = cls_cmd_id;

			EmberStatus status = EMBER_SUCCESS;

			uint16_t payload_len = 0;
			// Check whether the length is legal.
			if( tmpLength + payload_len < sizeof(tmpZclBuffer)) {
				// put in the ZCL payload content.
				tmpLength += 0;

				extern EmberApsFrame globalApsFrame;
				uint8_t src_ep =  kCmdGetEndpointByCluserID(cluster, direction?CLUSTER_MASK_SERVER:CLUSTER_MASK_CLIENT);

				emAfApsFrameClusterIdSetup(cluster);
				emAfApsFrameEndpointSetup(src_ep, des_ep);
				//cliBufferPrint();
				iKonkeAfSelfPrint("-- ZCL-CMD ------\r\n");
				iKonkeAfSelfPrintBuffer(tmpZclBuffer, tmpLength, true);
				iKonkeAfSelfPrint("\r\n-----------------\r\n");

				// sending method.
				switch(delivery) {
					case (0x01):
					{
						status = emberAfSendBroadcast(target, &globalApsFrame, tmpLength, tmpZclBuffer);
						break;
					}
					case (0x02):
					{
						status = emberAfSendMulticast(target, &globalApsFrame, tmpLength, tmpZclBuffer);
						break;
					}
					default:
					{
						status = (target < EMBER_BROADCAST_ADDRESS)?emberAfSendUnicast(EMBER_OUTGOING_DIRECT, target, &globalApsFrame, tmpLength, tmpZclBuffer):
							emberAfSendBroadcast(target, &globalApsFrame, tmpLength, tmpZclBuffer);
						break;
					}
				}
			}else {
				status = EMBER_MESSAGE_TOO_LONG;
			}

			if( status == EMBER_SUCCESS ) {

			}else {

			}

			break;
		}
		case (ECMD_READ_ATTR_REQ):
		{
			uint16_t target  = (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[0], 4);
			uint8_t des_ep 	 = (uint8_t )kUtilsOct2Value(g_stCmdIncomingMager.param[1], 2);
			uint16_t cluster = (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[2], 4);
			uint8_t c_s 	 = (uint8_t )kUtilsOct2Value(g_stCmdIncomingMager.param[3], 2);
			uint16_t mfg_code= (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[4], 4);
			uint16_t attr_num= (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[5], 4);

			EmberStatus status = EMBER_SUCCESS;

			if( target == NODE_ID_LOCAL ) { // local read

					// get all attributes values
					g_u8GlobalLengthN1 = 0;

					for(int index = 0; index < attr_num; ++index ) {
						uint8_t value_buffer[128] = { 0 }, data_type = ZCL_UNKNOWN_ATTRIBUTE_TYPE;

						uint16_t attribute_id = 0;

						status = emAfReadAttribute(des_ep, cluster, attribute_id, (c_s?CLUSTER_MASK_SERVER:CLUSTER_MASK_CLIENT)
							, mfg_code, value_buffer, sizeof(value_buffer), &data_type);

						g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = (attribute_id >> 8) & 0xff;
						g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = (attribute_id >> 0) & 0xff;
						g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = status;

						// Check whether the property value is read correctly.
						if( status == EMBER_SUCCESS ) {
							uint16_t data_length = (uint16_t)kUtilsGetDataLength(data_type);

							g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = data_type;

							if( data_length > 0 ) {
								kUtilsReverseArrayU8int(value_buffer, data_length, true);
								g_u8GlobalLengthN1 += data_length;
							}else if((data_type == ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE) || (data_type == ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE) ||
								(data_type == ZCL_ARRAY_ATTRIBUTE_TYPE) || (data_type == ZCL_STRUCT_ATTRIBUTE_TYPE) ||
								(data_type == ZCL_SET_ATTRIBUTE_TYPE) || (data_type == ZCL_BAG_ATTRIBUTE_TYPE)) {
								data_length = U16MERG(value_buffer[1], value_buffer[0]);

								g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = value_buffer[1];
								g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = value_buffer[0];

								memcpy(g_u8GlobalBufferN1 + g_u8GlobalLengthN1, value_buffer + 2, data_length);
								g_u8GlobalLengthN1 += data_length;
							}else {
								data_length = value_buffer[0];
								g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = value_buffer[0];
								memcpy(g_u8GlobalBufferN1 + g_u8GlobalLengthN1, value_buffer + 1, data_length);
								g_u8GlobalLengthN1 += data_length;
							}
						}
					}
			}else { // global read
				uint8_t zcl_seq = ZCLAPP_NEXT_SEQ();
				uint8_t src_ep  = kCmdGetEndpointByCluserID(cluster, c_s?CLUSTER_MASK_CLIENT:CLUSTER_MASK_SERVER);

				extern uint8_t appZclBuffer[];
				extern uint16_t appZclBufferLen;
				extern uint16_t mfgSpecificId;

				uint8_t mask = c_s?ZCL_FRAME_CONTROL_CLIENT_TO_SERVER:ZCL_FRAME_CONTROL_SERVER_TO_CLIENT;

				mfgSpecificId = mfg_code;
				zclBufferSetup(ZCL_GLOBAL_COMMAND | mask, cluster, ZCL_READ_ATTRIBUTES_COMMAND_ID);
				mfgSpecificId = EMBER_AF_NULL_MANUFACTURER_CODE;

				for(int index = 0; index < attr_num; ++index ) {
					zclBufferAddWord((uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[5] + 4 + (4 * index), 4));
				}

				emAfApsFrameEndpointSetup(src_ep, des_ep);
				// sending method.
				status = emberAfSendUnicast(EMBER_OUTGOING_DIRECT, target, &globalApsFrame, appZclBufferLen, appZclBuffer);
				if( status == EMBER_SUCCESS ) {

				}else {

				}
			}

			break;
		}
		case (ECMD_WRITE_ATTR_REQ):
		{
			uint16_t target  = 0;
			uint8_t des_ep 	 = 0;
			uint16_t cluster = 0;
			uint8_t c_s 	 = 0;
			uint16_t mfg_code = 0;

			g_u8GlobalLengthN2 = 0;

			EmberStatus status = EMBER_SUCCESS;

			if( target == NODE_ID_LOCAL ) { // local write

					// get all attributes values
					g_u8GlobalLengthN1 = 0;

					for(int index = 0; index < g_u8GlobalLengthN2; ) {
						uint16_t attribute_id = U16MERG(g_u8GlobalBufferN2[index + 0], g_u8GlobalBufferN2[index + 1]);
						uint8_t data_type = g_u8GlobalBufferN2[index + 2];

						status = emAfWriteAttribute(des_ep, cluster, attribute_id, (c_s?CLUSTER_MASK_SERVER:CLUSTER_MASK_CLIENT)
							, mfg_code, g_u8GlobalBufferN2 + index + 3, data_type, true, false);

						// Check whether the property value is read correctly.
						if( status != EMBER_SUCCESS ) {
							g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = status;
							g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = (attribute_id >> 8) & 0xff;
							g_u8GlobalBufferN1[g_u8GlobalLengthN1++] = (attribute_id >> 0) & 0xff;
						}

						uint16_t data_length = (uint16_t)kUtilsGetDataLength(data_type);
						if( data_length == 0 ) {
							data_length = g_u8GlobalBufferN2[index + 3] + 1;
						}

						index += (3 + data_length);
				}
			}else { // global write
				uint8_t zcl_seq = ZCLAPP_NEXT_SEQ();
				uint8_t src_ep  = kCmdGetEndpointByCluserID(cluster, c_s?CLUSTER_MASK_CLIENT:CLUSTER_MASK_SERVER);

				extern uint8_t appZclBuffer[];
				extern uint16_t appZclBufferLen;
				extern uint16_t mfgSpecificId;

				uint8_t mask = c_s?ZCL_FRAME_CONTROL_CLIENT_TO_SERVER:ZCL_FRAME_CONTROL_SERVER_TO_CLIENT;

				mfgSpecificId = mfg_code;
				zclBufferSetup(ZCL_GLOBAL_COMMAND | mask, cluster, ZCL_WRITE_ATTRIBUTES_COMMAND_ID);
				mfgSpecificId = EMBER_AF_NULL_MANUFACTURER_CODE;

				// convert to small-end format.
				for(int index = 0; index < g_u8GlobalLengthN2; ) {
					kUtilsReverseArrayU8int(g_u8GlobalBufferN2 + index, 2, true);

					uint16_t data_type   = g_u8GlobalBufferN2[index + 2];
					uint16_t data_length = (uint16_t)kUtilsGetDataLength(data_type);
					if( data_length > 0 ) {
						kUtilsReverseArrayU8int(g_u8GlobalBufferN2 + index + 3, data_length, true);
					}else if((data_type == ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE) || (data_type == ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE) ||
						(data_type == ZCL_ARRAY_ATTRIBUTE_TYPE) || (data_type == ZCL_STRUCT_ATTRIBUTE_TYPE) ||
						(data_type == ZCL_SET_ATTRIBUTE_TYPE) || (data_type == ZCL_BAG_ATTRIBUTE_TYPE)) {

						data_length = U16MERG(g_u8GlobalBufferN2[index + 3], g_u8GlobalBufferN2[index + 4]) + 2;
						kUtilsReverseArrayU8int(g_u8GlobalBufferN2 + index + 3, 2, true);
					}else {
						data_length = g_u8GlobalBufferN2[index + 3] + 1;
					}

					index += (3 + data_length);
				}

				zclBufferAddBuffer(g_u8GlobalBufferN2, g_u8GlobalLengthN2);
				emAfApsFrameEndpointSetup(src_ep, des_ep);

				// sending method.
				status = emberAfSendUnicast(EMBER_OUTGOING_DIRECT, target, &globalApsFrame, appZclBufferLen, appZclBuffer);
				if( status == EMBER_SUCCESS ) {

				}else {

				}
			}

			break;
		}
#endif
#if 0
		case (ECMD_GET_RSSI_REQ):
		{
			EmberStatus status = EMBER_SUCCESS;
			int8_t rssi_nd = -127;
			uint8_t index_tmp = 0;

			uint16_t target = (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[0], 4);

			if(!getEndDeviceRssiByNodeid(target, &rssi_nd, &index_tmp)) {
				status = EMBER_NOT_FOUND;
			}

			err = kCmdOutgoingCommandSetUp(ECMD_GET_RSSI_ACK, NODE_ID_LOCAL, ENDPOINT_UNKNOW, CLUSTER_UNKNOW, CLUSTER_CMD_UNKNOW, TRANSMIT_SEQ_UNKNOW);
			if( err == KET_OK ) {
				kCmdOutgoingCommandPutInU8int(status, true);
				kCmdOutgoingCommandPutInU16int(target, true);
				kCmdOutgoingCommandPutInInt(rssi_nd, true);
				kCmdOutgoingCommandSent();
			}

			break;
		}
#endif
#if 0
		case (ECMD_OOD_CMD_REQ):
		{
			uint16_t target = (uint16_t)kUtilsOct2Value(g_stCmdIncomingMager.param[0], 4);
			uint32_t dev_id = (uint32_t)kUtilsOct2Value(g_stCmdIncomingMager.param[1], 8);

			// Integrate complete private-ood data package.
			g_u8GlobalLengthN2 = 0;
			// zcl attribute id
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (OPTTUNNEL_OPTDATA_ID >>  0) & 0xff;
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (OPTTUNNEL_OPTDATA_ID >>  1) & 0xff;
			// zcl attribute type
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = ZCL_CHAR_STRING_ATTRIBUTE_TYPE;
			// zcl attribute value length
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = 0;

			// ood length
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = 0;
			// device id
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (dev_id >> 24) & 0xff;
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (dev_id >> 16) & 0xff;
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (dev_id >>  8) & 0xff;
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (dev_id >>  0) & 0xff;
			// channel
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (uint8_t )kUtilsOct2Value(g_stCmdIncomingMager.param[2], 2);
			// opcode
			g_u8GlobalBufferN2[g_u8GlobalLengthN2++] = (uint8_t )kUtilsOct2Value(g_stCmdIncomingMager.param[3], 2);
			// payload
			g_u8GlobalLengthN2 += kUtilsStr2Hex(g_stCmdIncomingMager.param[4] + 4, g_u8GlobalBufferN2 + g_u8GlobalLengthN2, GLOBAL_BUFFER_SIZE - g_u8GlobalLengthN2);

			// reset attribute value length
			g_u8GlobalBufferN2[3] = g_u8GlobalLengthN2 - 4;
			// reset ood length
			g_u8GlobalBufferN2[4] = g_u8GlobalLengthN2 - 4 - 1;

			extern uint8_t appZclBuffer[];
			extern uint16_t appZclBufferLen;
			extern uint16_t mfgSpecificId;

			mfgSpecificId = EMBER_AF_NULL_MANUFACTURER_CODE;
			zclBufferSetup(ZCL_GLOBAL_COMMAND | ZCL_FRAME_CONTROL_CLIENT_TO_SERVER, PRIV_CLUSTER_FCC0, ZCL_WRITE_ATTRIBUTES_COMMAND_ID);
			zclBufferAddBuffer(g_u8GlobalBufferN2, g_u8GlobalLengthN2);

			uint8_t zcl_seq = ZCLAPP_NEXT_SEQ();

			// sending method.
			EmberStatus status = emberAfSendUnicast(EMBER_OUTGOING_DIRECT, target, &globalApsFrame, appZclBufferLen, appZclBuffer);
			if( status == EMBER_SUCCESS ) {
				err = KET_ERR_OPRATE_IN_PROGRESS;
			}else {
				err = kCmdOutgoingCommandSetUp(ECMD_OOD_CMD_ACK, target, ENDPOINT_UNKNOW, CLUSTER_UNKNOW, CLUSTER_CMD_UNKNOW, zcl_seq);
				if( err == KET_OK ) {
					kCmdOutgoingCommandPutInU8int(status, true);
					kCmdOutgoingCommandPutInU16int(target, true);
					kCmdOutgoingCommandPutInU32int(dev_id, true);
					kCmdOutgoingCommandPutInOctetString(g_stCmdIncomingMager.param[2], true);
					kCmdOutgoingCommandPutInOctetString(g_stCmdIncomingMager.param[3], true);
					kCmdOutgoingCommandPutInU16int(0x0000, true);
					kCmdOutgoingCommandSent();
				}
			}

			break;
		}
#endif
		//add bby maozj 20191220
		case (UART_MSG_JOIN_NWK_REQUEST_OPCODE):
		{
			extern void kNwkFactoryReset(bool is_nwk_indicator);
			extern void kNwkJoiningStart(uint32_t u32JoiningDuration, pJoinCompleteCallback callback );
			uint8_t status = 0x00;

			uint8_t duration = data.u8ARG[0];//unit:S

			if (emberNetworkState() == EMBER_JOINED_NETWORK || emberNetworkState() == EMBER_JOINED_NETWORK ){
				iKonkeAfSelfPrint("#####NWK Is Joined By Usart Duration(0x%2x)\r\n", duration);
				send_buf.u8ARG[0] = ERR_NOT_EXPECTED;
			}else {
				send_buf.u8ARG[0] = ERR_OK;
				kNwkFactoryReset(false);
				//steering timeout can be set
				iKonkeAfSelfPrint("#####Start Steering By Usart Duration(0x%2x)\r\n", duration);
				kNwkJoiningStart(duration * 1000, NULL);
			}
			send_buf.u8Datalen = 5;
			//kkUartMsgSent(&send_buf);
			kCmdMsgDataSent(Z_TO_H_NO_ACK, send_buf, false);
			break;
		}
		default:
		{
			break;
		}
	}
}

#endif
