/**********************************************************************
 * INCLUDES
 */
#include "ikk-opt-tunnel.h"
#include "ikk-debug.h"
#include "ikk-config.h"
#include "ikk-token.h"
#include "../../../../zigbee/zcl/zcl_include.h"
#include "ikk-command.h"
#include "../driver/ikk-uart.h"
#include "ikk-factory-test.h"
#include "ikk-common-utils.h"

// FCC0-0000
#pragma pack(1)
typedef struct tag_private_clsFCC0_attr0000_frame_st {
	unsigned char length;	// frame length - not include itself!!!
	unsigned int  device_id;// device id
	unsigned char channel;	// channel
	unsigned char opcode;	// pocode
	unsigned char arg[OPTTUNNEL_OPTDATA_MAXLEN - 7]; // opcode arg
}
__attribute__((packed)) OptTunnelOptDataFrameSt;



uint8_t g_tmp_buffer[OPTTUNNEL_CHUNK_MAXLEN+1] = { 0 }, g_tmp_length = 0;

// private protocol optdata message incoming process callback
pFUNC_OPTDATA_MESSAGE_CALLBACK g_pOptDataIncomingMessageCallback = NULL;

extern bool  Get_Model_ID(uint8_t *ModeID);
extern _CODE_ZCL_ zclReadCmd_t *zcl_parseInReadCmd(zclIncoming_t *pCmd);
extern _CODE_ZCL_ status_t zcl_readRsp(u8 srcEp, epInfo_t *pDstEpInfo, u16 clusterId, u16 manuCode, u8 disableDefaultRsp, u8 direction, u8 seqNo, zclReadRspCmd_t *readRspCmd);

void kOptTunneCheckNodeIdIsChangedReport(void)
{
	uint16_t currentNodeId= 0x1234;
	uint16_t savedNodeId;
	if (zb_isDeviceJoinedNwk()){
		savedNodeId = kNwkgetNodeIdFromFlash();
		currentNodeId = zb_getLocalShortAddr();
		//iKonkeAfSelfPrint("!!!checkNodeIdIsChanged savedNodeId = %d, currentNodeId = %d\r\n", savedNodeId, currentNodeId);
		if (savedNodeId != currentNodeId){
			//report AssociateAnnounce attr of private cluster
			iKonkeAfSelfPrint("!!!checkNodeIdIsChanged savedNodeId = %d, currentNodeId = %d\r\n", savedNodeId, currentNodeId);
			if (savedNodeId != 0xFFFF){
				kOptTunnelCommonReport(ECA_ASSOCIATED_AOUNCE);
			}
			//save changed nodeId to flash
			kNwksaveNodeIdToFlash(currentNodeId);
		}
	}
}

uint8_t kOptTunnelChunkRead(uint8_t endpoint,
							uint16_t clusterId,
							uint16_t attributeId,
							uint16_t manufacturerCode,
							uint8_t *buffer,
							uint8_t *length_out)
{
	iKonkeAfSelfPrint("&&&&&&&&&&&&&Token Read cluster(%d), attr(%d)\r\n", clusterId, attributeId);
	uint8_t length = 0;
	if (buffer == NULL){
		iKonkeAfSelfPrint("Err: Buffer is null(%d)!!\r\n");
		return 0xff;
	}

	if( clusterId == PRIV_CLUSTER_FCC0 ) {
		switch(attributeId) {
			case (ZCL_CMEI_ATTRIBUTE_ID):
			{
				uint8_t *data = CMEI_TOKEN_GET();
				length = data[0];
				memcpy(buffer, data, length+1);
				break;
			}
			case (ZCL_ISN_ATTRIBUTE_ID):
			{
				uint8_t *data = ISN_TOKEN_GET();
				length = data[0];
				memcpy(buffer, data, length+1);
				break;
			}
			case (ZCL_InstallCode_ATTRIBUTE_ID):
			{
				length = 16;
				buffer[0] 		 = length;
				memcpy(&buffer[1], INSTALL_CODE_TOKEN_GET(), length);
				break;
			}
			case (ZCL_CHUNK_N1_ATTRIBUTE_ID):
			{
				break;
			}
			default:
				return 0xfe;
		}
	}
	if (buffer[0] <= OPTTUNNEL_CHUNK_MAXLEN){
		*length_out = buffer[0];
	}else {
		*length_out = 0;
	}
	return 0;
}
/*	DESP: Private clsuter attribute read interface, for chunk data.
 * 	Auth: dingmz_frc.20190703.
 * */
kk_err_t kOptTunnelAttrChunkLocalRead(uint16_t attribute_id, unsigned char *chunk_buffer, unsigned char *length_in_out )
{
	if( NULL == chunk_buffer || NULL == length_in_out ) {
		return KET_ERR_INVALID_POINTER;
	}

	uint8_t status = 0;
	kk_err_t err = KET_OK;

	status = kOptTunnelChunkRead(1, PRIV_CLUSTER_FCC0, attribute_id, 0x1268,  chunk_buffer, length_in_out);
	if( status == 0 ) {
		*length_in_out = chunk_buffer[0] + 1;
	}else {
		iKonkeAfSelfPrint("Err: Chunk read err(%d)!!\r\n", status);
		*length_in_out = 0;
		err = KET_ERR_UNKNOW;
	}

	return err;
}
status_t kOptTunnelMessageReadResponse(zclIncoming_t *pInHdlrMsg,uint8_t *pData)
{
	u8 status = ZCL_STA_SUCCESS;
	u16 clusterId = pInHdlrMsg->msg->indInfo.cluster_id;
	u8 endpoint = pInHdlrMsg->msg->indInfo.dst_ep;

	/* Parse In Read Command */
	u8 *pBuf = pInHdlrMsg->pData;
	zclReadCmd_t pReadCmd ={0};
	pReadCmd.numAttr = pInHdlrMsg->dataLen / 2;	//attr ID
	for(u8 i = 0; i < pReadCmd.numAttr; i++){
		pReadCmd.attrID[i] = BUILD_U16(pBuf[0], pBuf[1]);
		pBuf += 2;
	}
	iKonkeAfSelfPrint("#########kOptTunnelMessageReadResponse111111 attr = %d,%d\r\n",pReadCmd.attrID[0],pReadCmd.numAttr);

	if(!pInHdlrMsg->msg->indInfo.security_status){
		status = ZCL_STA_FAILURE;
	}

	/* Build Read Response Command */
	u16 len = sizeof(zclReadRspCmd_t) + (pReadCmd.numAttr * sizeof(zclReadRspStatus_t));
	zclReadRspCmd_t *pReadRspCmd = (zclReadRspCmd_t *)ev_buf_allocate(len);
	if(!pReadRspCmd){
		return ZCL_STA_INSUFFICIENT_SPACE;
	}

	pReadRspCmd->numAttr = pReadCmd.numAttr;
	pReadRspCmd->attrList[0].attrID = pReadCmd.attrID[0];
	pReadRspCmd->attrList[0].status = status;
	pReadRspCmd->attrList[0].dataType = ZCL_DATA_TYPE_CHAR_STR;
	pReadRspCmd->attrList[0].data = pData;

	epInfo_t dstEp;
	TL_SETSTRUCTCONTENT(dstEp, 0);

	dstEp.dstEp = pInHdlrMsg->msg->indInfo.src_ep;
	dstEp.profileId = pInHdlrMsg->msg->indInfo.profile_id;
	dstEp.dstAddrMode = APS_SHORT_DSTADDR_WITHEP;
	dstEp.dstAddr.shortAddr = pInHdlrMsg->msg->indInfo.src_short_addr;
	dstEp.txOptions |= APS_TX_OPT_ACK_TX;
	if(pInHdlrMsg->msg->indInfo.security_status & SECURITY_IN_APSLAYER){
		dstEp.txOptions |= APS_TX_OPT_SECURITY_ENABLED;
	}
	status = zcl_readRsp(endpoint, &dstEp, clusterId, pInHdlrMsg->hdr.manufCode, false, !pInHdlrMsg->hdr.frmCtrl.bf.dir, pInHdlrMsg->hdr.seqNum, pReadRspCmd);

	//free data
	ev_buf_free((void *)pReadRspCmd);

	return status;
}
status_t kOptTunnelMessageWriteResponse(zclIncoming_t *pCmd,uint8_t *pData)
{
	u8 status = ZCL_STA_SUCCESS;
	u16 clusterId = pCmd->msg->indInfo.cluster_id;
	u8 endpoint = pCmd->msg->indInfo.dst_ep;
	uint8_t tmp_buffer[64] ={0};
	uint8_t i =0;
	uint8_t payload_len = pData[0];

	// 8 0 51 86 10 0 0 0 0
	if(pCmd->hdr.cmd == ZCL_CMD_WRITE){
		tmp_buffer[i++] = 0x00;
		tmp_buffer[i++] = ZCL_STA_SUCCESS;				//0
		tmp_buffer[i++] = 00;							//1
		tmp_buffer[i++] = 00;							//2
		tmp_buffer[i++] = ZCL_DATA_TYPE_CHAR_STR;		//3 type
		tmp_buffer[i++] = payload_len+1;				//4 len
		tmp_buffer[i++] = payload_len;					//5 len
		if(payload_len +7 < 64)
		{
			memcpy(&tmp_buffer[i],&pData[1],payload_len);
		}
		tmp_buffer[0] = payload_len + 6;
		epInfo_t dstEp;
		TL_SETSTRUCTCONTENT(dstEp, 0);

		dstEp.dstEp = pCmd->msg->indInfo.src_ep;
		dstEp.profileId = pCmd->msg->indInfo.profile_id;
		dstEp.dstAddrMode = APS_SHORT_DSTADDR_WITHEP;
		dstEp.dstAddr.shortAddr = pCmd->msg->indInfo.src_short_addr;
		dstEp.txOptions |= APS_TX_OPT_ACK_TX;
		if(pCmd->msg->indInfo.security_status & SECURITY_IN_APSLAYER){
			dstEp.txOptions |= APS_TX_OPT_SECURITY_ENABLED;
		}
		status = zcl_sendCmd(endpoint, &dstEp, clusterId, ZCL_CMD_WRITE_RSP, FALSE, !pCmd->hdr.frmCtrl.bf.dir, false, pCmd->hdr.manufCode, pCmd->hdr.seqNum, tmp_buffer[0], &tmp_buffer[1]);
	}
	return status;
}
/*	DESP: private protocol command process.
 * 	Auth: dingmz_frc.20190704.
 * */
kk_err_t kOptTunnelMessageIncoming(OptMethodEm method,zclIncoming_t *pCmd)
{
	kk_err_t status = KET_OK;
	// 0 0 42 7 6 0 51 86 10 0 0      oring data  zcl global write 0xfcc0 0x0000 0x42 {06 00 51 86 10 00 00}
	//out 6 0 51 86 10 0 0 0


	// device id
	uint32_t modeid = (uint32_t)MODEL_ID;
	uint16_t attribute_id = 0xffff;
	uint8_t tmp_buffer[6];
	tmp_buffer[0] = 5;
	tmp_buffer[1] = modeid>>24;
	tmp_buffer[2] = modeid>>16;
	tmp_buffer[3] = modeid>>8;
	tmp_buffer[4] = modeid;

	attribute_id = (pCmd->pData[1]>>8) + (pCmd->pData[0]);

	iKonkeAfSelfPrint("pData(1)=0x%x,pData(0)=0x%x,attribute_id=%d\r\n",pCmd->pData[1],pCmd->pData[0],attribute_id);
	switch(method) {
		case (EOM_WRITE):
		{
			uint8_t length = (uint8_t)pCmd->dataLen - 4;
			if( pCmd->pData ) {
				memcpy(g_tmp_buffer, pCmd->pData+4, length);
				g_tmp_length = length;
			}


			iKonkeAfSelfPrint("#######kOptTunnelMessageIncoming length(0x%d)\r\n", length);
			iKonkeAfSelfPrintBuffer(g_tmp_buffer,length);

			//copy device id

			memcpy(&g_tmp_buffer[1],&tmp_buffer[1],4);
//			switch(attribute_id)
//			{
//				case (ECA_OPTDATA):
//				{
					if( length >= 7 ) {
						iKonkeAfSelfPrint("\r\n########################OPTDATA WRITE,g_tmp_length = %d\r\n",g_tmp_length);
						extern kk_err_t kCmdGeneralMsgPaser(UMsgNodeSt *pMsgNode, ComPortEm port, DataField_st *pDataOut);
						UMsgNodeSt msgNode;
						DataField_st dataOut;

						// length pid ch opcode arg
						memcpy(msgNode.buffer, &g_tmp_buffer[0], g_tmp_length);
						msgNode.length = g_tmp_length;
						if (kCmdGeneralMsgPaser(&msgNode, ECOM_PORT_FCC0, &dataOut) == KET_OK) {
							iKonkeAfSelfPrint("length(%d)\r\n" , dataOut.u8Datalen);
							iKonkeAfSelfPrintBuffer(dataOut.u8ARG, dataOut.u8Datalen);
							g_tmp_length = dataOut.u8Datalen + 7;
							g_tmp_buffer[0] = g_tmp_length - 1;
							memcpy(&g_tmp_buffer[7], dataOut.u8ARG, dataOut.u8Datalen);
							kOptTunnelMessageWriteResponse(pCmd, g_tmp_buffer);
						} else if (kkFactoryMsgInComingPaser(&msgNode, ECOM_PORT_FCC0, &dataOut) == KET_OK) {
							iKonkeAfSelfPrint("length(%d)\r\n" , dataOut.u8Datalen);
							iKonkeAfSelfPrintBuffer(dataOut.u8ARG, dataOut.u8Datalen);
							g_tmp_length = dataOut.u8Datalen + 7;
							g_tmp_buffer[0] = g_tmp_length - 1;
							memcpy(&g_tmp_buffer[7], dataOut.u8ARG, dataOut.u8Datalen);
							kOptTunnelMessageWriteResponse(pCmd, g_tmp_buffer);
						}
						else if( g_pOptDataIncomingMessageCallback ) {
							g_tmp_length  = g_tmp_length - 6;
							if(KET_NO_RESPONSE == g_pOptDataIncomingMessageCallback(g_tmp_buffer[5], g_tmp_buffer[6], g_tmp_buffer + 7, &g_tmp_length)){
								return KET_NO_RESPONSE;
							}
							g_tmp_length += 7;
							g_tmp_buffer[0] = g_tmp_length - 1;
							iKonkeAfSelfPrint("#######kOptTunnelMessageIncoming11111 length(0x%2x)\r\n", g_tmp_buffer[0]);
							iKonkeAfSelfPrintBuffer(g_tmp_buffer,g_tmp_buffer[0]+1);
							kOptTunnelMessageWriteResponse(pCmd, g_tmp_buffer);
						}
					}else {
						return KET_ERR_INVALID_PARAM;
					}
//
//					break;
//				}
//			}
			break;
		}
		case (EOM_READ ):
		{
			switch(attribute_id){
				// OptData read command is same to write opcode 0x00, read the device snap.
				case (ECA_OPTDATA):
				{
					iKonkeAfSelfPrint("\r\n########################OPTDATA READ\r\n");
					if( g_pOptDataIncomingMessageCallback ) {
						memcpy(&g_tmp_buffer[2],&tmp_buffer[1],4);
						g_tmp_buffer[6] = 0x00;
						g_tmp_buffer[7] = 0x00;
						g_tmp_buffer[8] = 0x00;
						g_tmp_buffer[9] = 0x00;
						g_tmp_length = 0;
						g_pOptDataIncomingMessageCallback(0, 0, g_tmp_buffer + 8, &g_tmp_length);
						g_tmp_length += 7;
						g_tmp_buffer[0] = g_tmp_length;				//length
						g_tmp_buffer[1] = g_tmp_length - 1;			//string length
						kOptTunnelMessageReadResponse(pCmd, g_tmp_buffer);
					}
					break;
				}

				case (ECA_TTS):
				case (ECA_MTORR_RR):
				{
					kOptTunnelMessageReadResponse(pCmd, g_tmp_buffer);
				  break;
				}
				case (ECA_ASSOCIATED_AOUNCE):
				{
					addrExt_t u64LocalEui64 = { 0 };
					uint16_t NodeID = zb_getLocalShortAddr();

					uint16_t index;
					tl_zbExtAddrByShortAddr(NodeID,u64LocalEui64,&index);

					g_tmp_buffer[0] = (NodeID >> 8) & 0xff;
					g_tmp_buffer[1] = (NodeID >> 0) & 0xff;
					SWAP_EUI64(u64LocalEui64);

					memcpy(g_tmp_buffer + 2, u64LocalEui64, 8);
					g_tmp_length = 10;

					memmove(&g_tmp_buffer[1],&g_tmp_buffer[0],g_tmp_length);
					g_tmp_buffer[0] = g_tmp_length;
					kOptTunnelMessageReadResponse(pCmd, g_tmp_buffer);

					iKonkeAfSelfPrint("#########Token Get Buffer(length(%d)): ", g_tmp_length);
					iKonkeAfSelfPrintBuffer(g_tmp_buffer, g_tmp_length);
					iKonkeAfSelfPrint("\r\n");
					break;
				}
				case (ECA_CMEI):
				case (ECA_ISN ):
				case (ECA_CHUNK_N1):
				case (ECA_INSTALL_CODE):
				{
					g_tmp_length = OPTTUNNEL_CHUNK_MAXLEN;
					kk_err_t status = kOptTunnelAttrChunkLocalRead(attribute_id, g_tmp_buffer, &g_tmp_length);
					iKonkeAfSelfPrint("#########Token Get Buffer(length(%d)): ", g_tmp_length);
					if(g_tmp_length > 1){
						memmove(&g_tmp_buffer[1],&g_tmp_buffer[0],g_tmp_length);
						g_tmp_buffer[0] = g_tmp_length;
					}
					if (status == KET_OK){
						kOptTunnelMessageReadResponse(pCmd, g_tmp_buffer);
					}else {
						tmp_buffer[5] = ZCL_STA_FAILURE;
						kOptTunnelMessageReadResponse(pCmd, tmp_buffer);
					}
					break;
				}
			}
			g_tmp_length = 0;
			g_tmp_buffer[0] = 0;
			memset(g_tmp_buffer,0,32);
			break;
		}
		default: break;
	}

	return status;
}

/*	DESP: Private protocol message(command) reporting interface
 * 	Auth: dingmz_frc.20191113.
 * */
extern status_t General_Report(uint8_t src_ep,uint8_t des_ep,uint16_t cluster,uint16_t Attribute,uint8_t Data_Type,uint8_t *value);
static status_t kOptTunnelCommonReportSend(uint16_t attribute_id, uint8_t *arg, uint8_t length )
{
	uint8_t temp_buffer[64] = {0};
	if( arg && length > 0 )
		memmove(temp_buffer+1, arg, length);
	temp_buffer[0] = length;
	memmove(g_tmp_buffer,temp_buffer,length+1);

	return General_Report(1,1,PRIV_CLUSTER_FCC0,attribute_id,ZCL_DATA_TYPE_CHAR_STR,g_tmp_buffer);
}
/*	DESP: Private protocol common report interface.
 * 	Auth: dingmz_frc.20191113.
 * */
kk_err_t kOptTunnelCommonReport(uint16_t attribute_id)
{
	if( attribute_id == OPTTUNNEL_UNKNOW ) {
		return KET_ERR_NON_EXIST;
	}

	kk_err_t err = KET_OK;
	uint8_t bufCount = 0;
	switch(attribute_id) {
		case (ECA_OPTDATA):
		{
			uint8_t modeid[8] = {0};
			if(Get_Model_ID(modeid))
			{
				g_tmp_buffer[bufCount++]		= 0;
				g_tmp_buffer[bufCount++] 		= modeid[4];
				g_tmp_buffer[bufCount++] 		= modeid[5];
				g_tmp_buffer[bufCount++] 		= modeid[6];
				g_tmp_buffer[bufCount++] 		= modeid[7];
				g_tmp_buffer[5] = 0x00;//channel
				g_tmp_buffer[6] = 0x00;//opcode
			}
			if( g_pOptDataIncomingMessageCallback ) {
				g_tmp_length = 0;
				g_tmp_buffer[7] = 0x00;//add by maozj 20200511
				g_pOptDataIncomingMessageCallback(0, 0, g_tmp_buffer + 7, &g_tmp_length);
				g_tmp_length += 7;
				g_tmp_buffer[0] = g_tmp_length - 1;
			}else {
				err = KET_ERR_INVALID_POINTER;
			}
			break;
		}
		case (ECA_ASSOCIATED_AOUNCE):
		{
			addrExt_t u64LocalEui64 = { 0 };
			uint16_t NodeID = zb_getLocalShortAddr();

			uint16_t index;
			tl_zbExtAddrByShortAddr(NodeID,u64LocalEui64,&index);

			g_tmp_buffer[0] = (NodeID >> 8) & 0xff;
			g_tmp_buffer[1] = (NodeID >> 0) & 0xff;
			SWAP_EUI64(u64LocalEui64);

			memcpy(g_tmp_buffer + 2, u64LocalEui64, 8);
			g_tmp_length = 10;
			break;
		}
		case (ECA_CMEI):
		case (ECA_ISN):
		{
			g_tmp_length = OPTTUNNEL_CHUNK_MAXLEN;
			kOptTunnelAttrChunkLocalRead(attribute_id, g_tmp_buffer, &g_tmp_length);
			iKonkeAfSelfPrint("####Report CHUNK Read length(0x%x) \r\n", g_tmp_length);
			break;
		}
		case (ECA_INSTALL_CODE):
			g_tmp_length = OPTTUNNEL_CHUNK_MAXLEN;
			kOptTunnelAttrChunkLocalRead(ZCL_InstallCode_ATTRIBUTE_ID, g_tmp_buffer, &g_tmp_length);
			break;
		default:
		{
			err = KET_ERR_OPRATE_ILLEGAL;
			break;
		}
	}
	if( err == KET_OK  && g_tmp_length > 1) {
		if(kOptTunnelCommonReportSend(attribute_id,g_tmp_buffer,g_tmp_buffer[0]+1)== ZCL_STA_SUCCESS)
			err = KET_OK;
		else
			err = KET_FAILED;
	}

	g_tmp_length = 0;
	g_tmp_buffer[0] = 0;
	memset(g_tmp_buffer,0,32);

	return err;
}
/*	DESP: Private protocol message(command) reporting interface
 * 	Auth: dingmz_frc.20191113.
 * */

kk_err_t kOptTunnelOODReport(uint8_t channel, uint8_t opcode, uint8_t *arg, uint8_t length )
{
	uint8_t bufCount = 0;
	uint8_t modeid[8] = {0};
	if(Get_Model_ID(modeid))
	{
		g_tmp_buffer[bufCount++] 		= 0; // totle length
		g_tmp_buffer[bufCount++] 		= modeid[4];
		g_tmp_buffer[bufCount++] 		= modeid[5];
		g_tmp_buffer[bufCount++] 		= modeid[6];
		g_tmp_buffer[bufCount++] 		= modeid[7];
		g_tmp_buffer[bufCount++] 		= channel;//channel
		g_tmp_buffer[bufCount++] 		= opcode;//opcode
	}
	if( arg && length > 0 ) {
		memcpy(g_tmp_buffer + bufCount, arg, length);
		bufCount += length;
	}

	g_tmp_buffer[0] = bufCount - 1;

	return kOptTunnelCommonReportSend(ECA_OPTDATA, g_tmp_buffer, bufCount);
}
kk_err_t kOptTunnelModuleInit(pFUNC_OPTDATA_MESSAGE_CALLBACK pOptdataIncomingCallback )
{
	g_pOptDataIncomingMessageCallback = pOptdataIncomingCallback;

	return KET_OK;
}

uint8_t HexToASCII(uint8_t hex){
	if((hex>=0x0A)&&(hex<=0x0F))//´óÐ´×ÖÄ¸
        hex += 0x37;
	else if ((hex>=0x00)&&(hex<=0x09))
		hex += 0x30;
    else hex = 0xff;
    return hex;
}

//DESP: write default installcode.
bool kOptTunnelTrytoWriteInstallCode(void)
{
	OPTTUNEL_TOKEN_ST sOptunnel_Token_temp;
	flash_read(TOKEN_USER_LOCATION,USER_SIZE,(uint8_t*)&sOptunnel_Token_temp);
	if(All_Same_Data((uint8_t*)&sOptunnel_Token_temp.install_code.install_code_data,0xff,16)){

		addrExt_t long_address;
		zb_getLocalExtAddr(long_address);
		SWAP_EUI64((uint8_t *)long_address);//È¡·´

		uint8_t mac_address[16] = {0};
		for(uint8_t i=0;i<8;i++){//0-15
			mac_address[2*i] = long_address[i] >> 4;
			mac_address[2*i+1] = long_address[i] & 0x0f;
		}

		iKonkeAfSelfPrint("!!!MAC_address:\r\n");
		iKonkeAfSelfPrintBuffer(mac_address,16);

		for(uint8_t i=0;i<16;i++)
			mac_address[i] = HexToASCII(mac_address[i]);
		INSTALL_CODE_TOKEN_SET(mac_address,16);
	}
}
