#include "includes.h"


UINT8 Udp_IAP_sta = 0;           //升级服务状态
uint8_t TFTP_LOG_sta = 0;		 //TFTP LOG上传状态
uint32_t Udp_Internal_tick = 0;  //创建套接字使延时等待套接字稳定
IAPVarTypeStruct* IAPVarTypeStruct_Ptr = NULL;   //与局域网升级通讯相关的数据
tftp_connection_args* tftp_args = NULL;          //TFTP相关的数据

uint32_t ProjectCode = 1001;     		//模拟项目编码
UINT8 Versions[4] = {0,0,0,0};         	//模拟配置版本
uint16_t sever_port = 0;         		//存放局域网配置软件通讯的端口，主要用于测试回复升级结果（如果将其写入SRAM，则只需要从SRAM中读出）

/**
  * @brief  字节比较
  * @note   这个函数只比较length个字节长度的数据
  * @param  src:要比较的第一组字节的地址
  * @param  dst:要比较的第二组字节的地址
  * @param  length: 要比较的数据长度
  * @retval 0：字节不一样。
  * @retval 1：字节一样。
  */
uint8_t bytes_cmp(uint8_t* src,uint8_t* dst,const uint32_t length)
{
	uint32_t i =0;
	uint8_t  data_src=0;
	uint8_t  data_dst=0;
	for(i=0;i<length;i++)
	{
		data_src = *(src+i);
		data_dst = *(dst+i);
		if(data_src != data_dst)
		{
			return 1;
		}
	}
	return 0;
}

/**
  * @name  					硬件版本添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_ADD_SoftwareVer(uint8_t *data)
{
	uint8_t len = strlen(SoftwareVer);
	if(len > RCU_SoftwareVer)   len = RCU_SoftwareVer;     //防止版本号溢出死机
//	memcpy(data,SoftwareVer,sizeof(SoftwareVer));   //RCU_SoftwareVer
	memcpy(data,SoftwareVer,len);   //RCU_SoftwareVer
}

/**
  * @name  					配置版本添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_ADD_ConfigVer(uint8_t *data)
{
	//上电启动时，有赋值给Versions数组 添加配置版本
	data[0] = Versions[0];
	data[1] = Versions[1];
	data[2] = Versions[2];
}

/**
  * @name  					报文头添加
  * @param  
  *    data					网络数据包
  *    cmd  				命令
  *    length 			长度
  *    frame_no     帧号 
  * @retval 无
  */
void UDP_Add_Header(uint8_t *data,uint8_t cmd,uint16_t length, uint16_t frame_no)
{
	data[FRAME_HEAD_OFFSET]   = 0xAA;
	data[FRAME_HEAD_OFFSET+1] = 0x55;
	data[FRAME_LEN_OFFSET]    = length%256;
	data[FRAME_LEN_OFFSET+1]  = length/256;
	data[SYSTEM_ID_OFFSET]    = 'T';
	data[SYSTEM_ID_OFFSET +1] = '3';
	data[SYSTEM_ID_OFFSET +2] = 'S';
	data[SYSTEM_ID_OFFSET +3] = 'A';
	data[CMD_OFFSET] 	= cmd;
	data[FRAME_NO_OFFSET]     = frame_no%256;
	data[FRAME_NO_OFFSET +1]  = frame_no/256;
	data[FLOOR_NUM_OFFSET]    = ProjectCode%256;		//(FLASH_Flag.local_mac1>>16)%256;////项目编码 Project_code%256;
	data[FLOOR_NUM_OFFSET +1] = ProjectCode/256;		//(FLASH_Flag.local_mac1>>24)%256;////项目编码Project_code/256;

#if	NET_Head_Agreement_MAC_EN
	data[FLOOR_NUM_OFFSET +2] = MACAddr[4];   	//本机MAC地址后两位   
	data[FLOOR_NUM_OFFSET +3] = MACAddr[5];
#else
	data[FLOOR_NUM_OFFSET +2] = net_info.local_ip[2];   //本机ip
	data[FLOOR_NUM_OFFSET +3] = net_info.local_ip[3];
#endif

}

/**
  * @name  					服务器IP地址添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_Add_ServerIp(uint8_t *data)
{
	data[0] = server_info.dis_ip[0];
	data[1] = server_info.dis_ip[1];
	data[2] = server_info.dis_ip[2];
	data[3] = server_info.dis_ip[3];
}

/**
  * @name  					子网掩码添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_Add_Subnet(uint8_t *data)
{
	data[0] = net_info.mask[0];
	data[1] = net_info.mask[1];
	data[2] = net_info.mask[2];
	data[3] = net_info.mask[3];
}

/**
  * @name  					网关添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_Add_Gateway(uint8_t *data)
{
	data[0] = net_info.gwip_addr[0];
	data[1] = net_info.gwip_addr[1];
	data[2] = net_info.gwip_addr[2];
	data[3] = net_info.gwip_addr[3];
}

/**
  * @name  					网关添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_Add_Mac(uint8_t *data)
{
	data[0] = MACAddr[0];
	data[1] = MACAddr[1];
	data[2] = MACAddr[2];
	data[3] = MACAddr[3];
	data[4] = MACAddr[4];
	data[5] = MACAddr[5];
}

/**
  * @name  					机型添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_Add_Model(uint8_t *data)
{
	data[0] = 'T';
	data[1] = 'S';
	data[2] = 'W';
	data[3] = '1';
}

/**
  * @name  					端口号添加
  * @param  
  *    data					网络数据包
  * @retval 无
  */
void UDP_Add_Port(uint8_t *data)
{
	data[0] = 0x0D;				//3341%0x100;
	data[1] = 0x0D;				//3341/0x100;
}

/*
 * @name 子群发布，回复发布就绪
 * @para 
 *   data PC端发过来的整条报文
 *   ip  目标ip
 *   port 目标端口号
 * @return  为1表示成功，为2表示失败 
 */
uint8_t Udp_Internal_Subgroup(uint8_t* data, uint16_t DataLen, uint8_t*ip, uint16_t port)
{
	uint8_t state;
	uint8_t Ret = 0x02;
	if(DataLen != CONFIG_Cmd_Rev_Len)
	{
		return Ret;
	}
	server_info.goal_port = port;
	memcpy(server_info.goal_ip, ip, 4); //升级的IP地址，在接收完文件后，会保存重启
	uint8_t buff[6];
	memcpy(buff, ip, 4);
	buff[4] = port;
	buff[5] = port >> 8;
	SRAM_DMA_Write_Buff(buff, 6, SRAM_IAP_IP_ADDRESS);     //将配置工具的ip和port存入SRAM，回复升级结果时使用这个端口，而不是TFTP服务及文件传输的套接字
	sever_port = port;                                     //无SRAM时测试用存储的端口，因为ip不会变
	if(IAPVarTypeStruct_Ptr == NULL)
	{
		IAPVarTypeStruct_Ptr = (IAPVarTypeStruct*)malloc(sizeof(IAPVarTypeStruct));   //分配空间
		memset(IAPVarTypeStruct_Ptr, 0, sizeof(IAPVarTypeStruct));
	}
	
	
	IAPVarTypeStruct_Ptr->Md5[0] = data[HEAD_LEN+3];
	IAPVarTypeStruct_Ptr->Md5[1] = data[HEAD_LEN+2];
	IAPVarTypeStruct_Ptr->Md5[2] = data[HEAD_LEN+1];
	IAPVarTypeStruct_Ptr->Md5[3] = data[HEAD_LEN+0];
	
	IAPVarTypeStruct_Ptr->Md5[4] = data[HEAD_LEN+7];
	IAPVarTypeStruct_Ptr->Md5[5] = data[HEAD_LEN+6];
	IAPVarTypeStruct_Ptr->Md5[6] = data[HEAD_LEN+5];
	IAPVarTypeStruct_Ptr->Md5[7] = data[HEAD_LEN+4];
	
	IAPVarTypeStruct_Ptr->Md5[8] = data[HEAD_LEN+11];
	IAPVarTypeStruct_Ptr->Md5[9] = data[HEAD_LEN+10];
	IAPVarTypeStruct_Ptr->Md5[10] = data[HEAD_LEN+9];
	IAPVarTypeStruct_Ptr->Md5[11] = data[HEAD_LEN+8];
	
	IAPVarTypeStruct_Ptr->Md5[12] = data[HEAD_LEN+15];
	IAPVarTypeStruct_Ptr->Md5[13] = data[HEAD_LEN+14];
	IAPVarTypeStruct_Ptr->Md5[14] = data[HEAD_LEN+13];
	IAPVarTypeStruct_Ptr->Md5[15] = data[HEAD_LEN+12];
	
	IAPVarTypeStruct_Ptr->BlockSize =  data[HEAD_LEN+16] + (data[HEAD_LEN+17]<<8);
	IAPVarTypeStruct_Ptr->IapFileType = DATATYPE_CONFIG;                      //配置类型
	
	if((0 < IAPVarTypeStruct_Ptr->BlockSize)&&(IAPVarTypeStruct_Ptr->BlockSize <= CFG_MAX_BLOCK))
	{
		Ret = 0x01;
		state = CONFIG_Ready;                                          //发布就绪
		IAPVarTypeStruct_Ptr->IapState = IAPSTART;                                                     //升级开始
		IAPVarTypeStruct_Ptr->IapType = IAPTFTPWRITE;                                                  //升级类型为写
	}
	else
	{
		Ret = 0x02;
		state = CONFIG_Error_Block;                   //IAP_Error;     //块错误
	}
	
	uint8_t back_data[CONFIG_Cmd_Send_Len]={0};
	//处理要返回的数据帧
	UDP_Add_Header(back_data, Subgroup_Cmd, CONFIG_Cmd_Send_Len, 0xffff);                    //添加头部
	back_data[CONFIG_Cmd_Send_State] = state;
	NetCRC16(&back_data[0], CONFIG_Cmd_Send_Len);
	UINT32 sendlen = CONFIG_Cmd_Send_Len;
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);
		
	return Ret;
}

/**
	* @name 升级命令
	* @para 
	*   data 下发数据包
	*   ip 目标ip
	*   port 目标端口号
	* @return 无
	*/
uint8_t Udp_Internal_IAP(uint8_t* data,uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t back_data[IAP_Cmd_Send_Len]={0};
	uint16_t frameno = data[FRAME_NO_OFFSET] + (data[FRAME_NO_OFFSET+1]<<8);
	uint8_t Ret = 0x03;
	UINT32 sendlen = IAP_Cmd_Send_Len;
	uint8_t buff[6];
	
	if(DataLen != IAP_Cmd_Rev_Len)
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"数据长度不对");
		return Ret;
	}
	
	server_info.goal_port = port;
	memcpy(server_info.goal_ip, ip, 4); //升级的IP地址，在接收完文件后，会保存重启

	memcpy(buff, ip, 4);
	buff[4] = port;
	buff[5] = port >> 8;
	SRAM_DMA_Write_Buff(buff, 6, SRAM_IAP_IP_ADDRESS);     //将配置工具的ip和port存入SRAM，回复升级结果时使用这个端口，而不是TFTP服务及文件传输的套接字
	sever_port = port;                                     //无SRAM时测试用存储的端口，因为ip不会变
	if(IAPVarTypeStruct_Ptr == NULL)
	{
		Dbg_Print(DBG_BIT_NET_STATUS_bit,"分配TFTP IAP空间");
		IAPVarTypeStruct_Ptr = (IAPVarTypeStruct*)malloc(sizeof(IAPVarTypeStruct));   //分配空间
	}
	memset(IAPVarTypeStruct_Ptr, 0, sizeof(IAPVarTypeStruct));
	
	IAPVarTypeStruct_Ptr->IapFileType = DATATYPE_IAP;				//文件类型
	IAPVarTypeStruct_Ptr->BlockSize   = (data[IAP_Cmd_Rev_Block]) + (data[IAP_Cmd_Rev_Block+1]<<8);
	
	IAPVarTypeStruct_Ptr->Md5[0]      = data[IAP_Cmd_Rev_Md5 + 3];
	IAPVarTypeStruct_Ptr->Md5[1]      = data[IAP_Cmd_Rev_Md5 + 2];
	IAPVarTypeStruct_Ptr->Md5[2]      = data[IAP_Cmd_Rev_Md5 + 1];
	IAPVarTypeStruct_Ptr->Md5[3]      = data[IAP_Cmd_Rev_Md5 + 0];
	
	IAPVarTypeStruct_Ptr->Md5[4]      = data[IAP_Cmd_Rev_Md5 + 7];
	IAPVarTypeStruct_Ptr->Md5[5]      = data[IAP_Cmd_Rev_Md5 + 6];
	IAPVarTypeStruct_Ptr->Md5[6]      = data[IAP_Cmd_Rev_Md5 + 5];
	IAPVarTypeStruct_Ptr->Md5[7]      = data[IAP_Cmd_Rev_Md5 + 4];
	
	IAPVarTypeStruct_Ptr->Md5[8]      = data[IAP_Cmd_Rev_Md5 + 11];
	IAPVarTypeStruct_Ptr->Md5[9]      = data[IAP_Cmd_Rev_Md5 + 10];
	IAPVarTypeStruct_Ptr->Md5[10]     = data[IAP_Cmd_Rev_Md5 + 9];
	IAPVarTypeStruct_Ptr->Md5[11]     = data[IAP_Cmd_Rev_Md5 + 8];
	
	IAPVarTypeStruct_Ptr->Md5[12]     = data[IAP_Cmd_Rev_Md5 + 15];
	IAPVarTypeStruct_Ptr->Md5[13]     = data[IAP_Cmd_Rev_Md5 + 14];
	IAPVarTypeStruct_Ptr->Md5[14]     = data[IAP_Cmd_Rev_Md5 + 13];
	IAPVarTypeStruct_Ptr->Md5[15]     = data[IAP_Cmd_Rev_Md5 + 12];
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP Md5:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",\
	IAPVarTypeStruct_Ptr->Md5[0],IAPVarTypeStruct_Ptr->Md5[1],\
	IAPVarTypeStruct_Ptr->Md5[2],IAPVarTypeStruct_Ptr->Md5[3],\
	IAPVarTypeStruct_Ptr->Md5[4],IAPVarTypeStruct_Ptr->Md5[5],\
	IAPVarTypeStruct_Ptr->Md5[6],IAPVarTypeStruct_Ptr->Md5[7],\
	IAPVarTypeStruct_Ptr->Md5[8],IAPVarTypeStruct_Ptr->Md5[9],\
	IAPVarTypeStruct_Ptr->Md5[10],IAPVarTypeStruct_Ptr->Md5[11],\
	IAPVarTypeStruct_Ptr->Md5[12],IAPVarTypeStruct_Ptr->Md5[13],\
	IAPVarTypeStruct_Ptr->Md5[14],IAPVarTypeStruct_Ptr->Md5[15]);
	
	
	//处理要返回的数据帧
	UDP_Add_Header(back_data,data[CMD_OFFSET],IAP_Cmd_Send_Len,frameno);                                    //添加头部
	if((0 < IAPVarTypeStruct_Ptr->BlockSize)||(IAPVarTypeStruct_Ptr->BlockSize <= RUN_MAX_BLOCK))       	//IAP_VarEx.block_size
	{
		Ret = 0x01;
		back_data[IAP_Cmd_Send_State] = IAP_Ready; 					//升级就绪
		IAPVarTypeStruct_Ptr->IapState = IAPSTART;           		//升级开始
		IAPVarTypeStruct_Ptr->IapType = IAPTFTPWRITE;    			//升级类型为写
		
		IAPVarTypeStruct_Ptr->processing_tick = SysTick_1ms;
	}
	else
	{
		Ret = 0x02;
		back_data[IAP_Cmd_Send_State] = IAP_Error;
	}
	UDP_ADD_SoftwareVer(&back_data[IAP_Cmd_Send_SoftwareVer]); 		//添加固件版本
	
	NetCRC16(&back_data[0],IAP_Cmd_Send_Len);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , IP:%d.%d.%d.%d , port:%d",net_info.SocketId[0],ip[0],ip[1],ip[2],ip[3],port);
	
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);	//回复升级就绪
	
	return Ret;
}

/*******************************************************************************
* Function Name  : Udp_Internal_BLVIAP
* Description    : BLV_Cx系列升级命令 - 发送数据内容与之前一样
* Input     	: 
* Return         : None
*******************************************************************************/
uint8_t Udp_Internal_BLVIAP(uint8_t* data,uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t back_data[IAP_Cmd_Send_Len]={0};
	uint16_t frameno = data[FRAME_NO_OFFSET] + (data[FRAME_NO_OFFSET+1]<<8);
	uint8_t Ret = 0x03;
	UINT32 sendlen = IAP_Cmd_Send_Len;
	
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	if(DataLen != IAP_Cmd_Rev_Len)
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"数据长度不对");
		return Ret;
	}
	
	server_info.goal_port = port;
	memcpy(server_info.goal_ip, ip, 4); //升级的IP地址，在接收完文件后，会保存重启
	uint8_t buff[6];
	memcpy(buff, ip, 4);
	buff[4] = port;
	buff[5] = port >> 8;
	SRAM_DMA_Write_Buff(buff, 6, SRAM_IAP_IP_ADDRESS);     //将配置工具的ip和port存入SRAM，回复升级结果时使用这个端口，而不是TFTP服务及文件传输的套接字
	sever_port = port;                                     //无SRAM时测试用存储的端口，因为ip不会变
	if(IAPVarTypeStruct_Ptr == NULL)
	{
		Dbg_Print(DBG_BIT_NET_STATUS_bit,"分配TFTP IAP空间");
		IAPVarTypeStruct_Ptr = (IAPVarTypeStruct*)malloc(sizeof(IAPVarTypeStruct));   //分配空间
	}
	memset(IAPVarTypeStruct_Ptr, 0, sizeof(IAPVarTypeStruct));
	
	IAPVarTypeStruct_Ptr->NewIapFlag = 0x01;	//BLV_Cx升级流程
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"文件类型:升级文件");
	IAPVarTypeStruct_Ptr->IapFileType = DATATYPE_IAP;				//文件类型
	IAPVarTypeStruct_Ptr->BlockSize   = (data[IAP_Cmd_Rev_Block]) + (data[IAP_Cmd_Rev_Block+1]<<8);
	
	IAPVarTypeStruct_Ptr->Md5[0]      = data[IAP_Cmd_Rev_Md5 + 3];
	IAPVarTypeStruct_Ptr->Md5[1]      = data[IAP_Cmd_Rev_Md5 + 2];
	IAPVarTypeStruct_Ptr->Md5[2]      = data[IAP_Cmd_Rev_Md5 + 1];
	IAPVarTypeStruct_Ptr->Md5[3]      = data[IAP_Cmd_Rev_Md5 + 0];
	
	IAPVarTypeStruct_Ptr->Md5[4]      = data[IAP_Cmd_Rev_Md5 + 7];
	IAPVarTypeStruct_Ptr->Md5[5]      = data[IAP_Cmd_Rev_Md5 + 6];
	IAPVarTypeStruct_Ptr->Md5[6]      = data[IAP_Cmd_Rev_Md5 + 5];
	IAPVarTypeStruct_Ptr->Md5[7]      = data[IAP_Cmd_Rev_Md5 + 4];
	
	IAPVarTypeStruct_Ptr->Md5[8]      = data[IAP_Cmd_Rev_Md5 + 11];
	IAPVarTypeStruct_Ptr->Md5[9]      = data[IAP_Cmd_Rev_Md5 + 10];
	IAPVarTypeStruct_Ptr->Md5[10]     = data[IAP_Cmd_Rev_Md5 + 9];
	IAPVarTypeStruct_Ptr->Md5[11]     = data[IAP_Cmd_Rev_Md5 + 8];
	
	IAPVarTypeStruct_Ptr->Md5[12]     = data[IAP_Cmd_Rev_Md5 + 15];
	IAPVarTypeStruct_Ptr->Md5[13]     = data[IAP_Cmd_Rev_Md5 + 14];
	IAPVarTypeStruct_Ptr->Md5[14]     = data[IAP_Cmd_Rev_Md5 + 13];
	IAPVarTypeStruct_Ptr->Md5[15]     = data[IAP_Cmd_Rev_Md5 + 12];
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP Md5:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",\
	IAPVarTypeStruct_Ptr->Md5[0],IAPVarTypeStruct_Ptr->Md5[1],\
	IAPVarTypeStruct_Ptr->Md5[2],IAPVarTypeStruct_Ptr->Md5[3],\
	IAPVarTypeStruct_Ptr->Md5[4],IAPVarTypeStruct_Ptr->Md5[5],\
	IAPVarTypeStruct_Ptr->Md5[6],IAPVarTypeStruct_Ptr->Md5[7],\
	IAPVarTypeStruct_Ptr->Md5[8],IAPVarTypeStruct_Ptr->Md5[9],\
	IAPVarTypeStruct_Ptr->Md5[10],IAPVarTypeStruct_Ptr->Md5[11],\
	IAPVarTypeStruct_Ptr->Md5[12],IAPVarTypeStruct_Ptr->Md5[13],\
	IAPVarTypeStruct_Ptr->Md5[14],IAPVarTypeStruct_Ptr->Md5[15]);
	
	
	//处理要返回的数据帧
	//UDP_Add_Header(back_data,data[CMD_OFFSET],IAP_Cmd_Send_Len,frameno);                                    //添加头部
	UDP_Add_Header(back_data,IAP_Cmd,IAP_Cmd_Send_Len,frameno);                                    //添加头部
	if((0 < IAPVarTypeStruct_Ptr->BlockSize)||(IAPVarTypeStruct_Ptr->BlockSize <= RUN_MAX_BLOCK))       	//IAP_VarEx.block_size
	{
		Ret = 0x01;
		back_data[IAP_Cmd_Send_State] = IAP_Ready; 					//升级就绪
		IAPVarTypeStruct_Ptr->IapState = IAPSTART;           		//升级开始
		IAPVarTypeStruct_Ptr->IapType = IAPTFTPWRITE;    			//升级类型为写
		
		IAPVarTypeStruct_Ptr->processing_tick = SysTick_1ms;
	}
	else
	{
		Ret = 0x02;
		back_data[IAP_Cmd_Send_State] = IAP_Error;
	}
	UDP_ADD_SoftwareVer(&back_data[IAP_Cmd_Send_SoftwareVer]); 		//添加固件版本
	
	NetCRC16(&back_data[0],IAP_Cmd_Send_Len);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , IP:%d.%d.%d.%d , port:%d",net_info.SocketId[0],ip[0],ip[1],ip[2],ip[3],port);
	
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);	//回复升级就绪
	
	return Ret;
}


/*******************************************************************************
* Function Name  : Udp_Internal_BLVIAP
* Description    : BLV_Cx系列逻辑下发命令 - BLV-Cx逻辑文件下发
* Input     	: 
* Return         : None
*******************************************************************************/
uint8_t Udp_Internal_BLVIAP_Logic(uint8_t* data,uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t back_data[IAP_Cmd_Send_Len]={0};
	uint16_t frameno = data[FRAME_NO_OFFSET] + (data[FRAME_NO_OFFSET+1]<<8);
	uint8_t Ret = 0x03;
	UINT32 sendlen = IAP_Cmd_Send_Len;
	
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	if(DataLen != IAP_Cmd_Rev_Len)
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"数据长度不对");
		return Ret;
	}
	
	server_info.goal_port = port;
	memcpy(server_info.goal_ip, ip, 4); //升级的IP地址，在接收完文件后，会保存重启
	uint8_t buff[6];
	memcpy(buff, ip, 4);
	buff[4] = port;
	buff[5] = port >> 8;
	SRAM_DMA_Write_Buff(buff, 6, SRAM_IAP_IP_ADDRESS);     //将配置工具的ip和port存入SRAM，回复升级结果时使用这个端口，而不是TFTP服务及文件传输的套接字
	sever_port = port;                                     //无SRAM时测试用存储的端口，因为ip不会变
	if(IAPVarTypeStruct_Ptr == NULL)
	{
		Dbg_Print(DBG_BIT_NET_STATUS_bit,"分配TFTP IAP空间");
		IAPVarTypeStruct_Ptr = (IAPVarTypeStruct*)malloc(sizeof(IAPVarTypeStruct));   //分配空间
	}
	memset(IAPVarTypeStruct_Ptr, 0, sizeof(IAPVarTypeStruct));
	
	IAPVarTypeStruct_Ptr->NewIapFlag = 0x01;	//BLV_Cx升级流程
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"文件类型:项目逻辑文件");
	IAPVarTypeStruct_Ptr->IapFileType = DATATYPE_CONFIG;				//文件类型
	IAPVarTypeStruct_Ptr->BlockSize   = (data[IAP_Cmd_Rev_Block]) + (data[IAP_Cmd_Rev_Block+1]<<8);
	
	IAPVarTypeStruct_Ptr->Md5[0]      = data[IAP_Cmd_Rev_Md5 + 3];
	IAPVarTypeStruct_Ptr->Md5[1]      = data[IAP_Cmd_Rev_Md5 + 2];
	IAPVarTypeStruct_Ptr->Md5[2]      = data[IAP_Cmd_Rev_Md5 + 1];
	IAPVarTypeStruct_Ptr->Md5[3]      = data[IAP_Cmd_Rev_Md5 + 0];
	
	IAPVarTypeStruct_Ptr->Md5[4]      = data[IAP_Cmd_Rev_Md5 + 7];
	IAPVarTypeStruct_Ptr->Md5[5]      = data[IAP_Cmd_Rev_Md5 + 6];
	IAPVarTypeStruct_Ptr->Md5[6]      = data[IAP_Cmd_Rev_Md5 + 5];
	IAPVarTypeStruct_Ptr->Md5[7]      = data[IAP_Cmd_Rev_Md5 + 4];
	
	IAPVarTypeStruct_Ptr->Md5[8]      = data[IAP_Cmd_Rev_Md5 + 11];
	IAPVarTypeStruct_Ptr->Md5[9]      = data[IAP_Cmd_Rev_Md5 + 10];
	IAPVarTypeStruct_Ptr->Md5[10]     = data[IAP_Cmd_Rev_Md5 + 9];
	IAPVarTypeStruct_Ptr->Md5[11]     = data[IAP_Cmd_Rev_Md5 + 8];
	
	IAPVarTypeStruct_Ptr->Md5[12]     = data[IAP_Cmd_Rev_Md5 + 15];
	IAPVarTypeStruct_Ptr->Md5[13]     = data[IAP_Cmd_Rev_Md5 + 14];
	IAPVarTypeStruct_Ptr->Md5[14]     = data[IAP_Cmd_Rev_Md5 + 13];
	IAPVarTypeStruct_Ptr->Md5[15]     = data[IAP_Cmd_Rev_Md5 + 12];
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP Md5:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",\
	IAPVarTypeStruct_Ptr->Md5[0],IAPVarTypeStruct_Ptr->Md5[1],\
	IAPVarTypeStruct_Ptr->Md5[2],IAPVarTypeStruct_Ptr->Md5[3],\
	IAPVarTypeStruct_Ptr->Md5[4],IAPVarTypeStruct_Ptr->Md5[5],\
	IAPVarTypeStruct_Ptr->Md5[6],IAPVarTypeStruct_Ptr->Md5[7],\
	IAPVarTypeStruct_Ptr->Md5[8],IAPVarTypeStruct_Ptr->Md5[9],\
	IAPVarTypeStruct_Ptr->Md5[10],IAPVarTypeStruct_Ptr->Md5[11],\
	IAPVarTypeStruct_Ptr->Md5[12],IAPVarTypeStruct_Ptr->Md5[13],\
	IAPVarTypeStruct_Ptr->Md5[14],IAPVarTypeStruct_Ptr->Md5[15]);
	
	
	//处理要返回的数据帧
	//UDP_Add_Header(back_data,data[CMD_OFFSET],IAP_Cmd_Send_Len,frameno);                                    //添加头部
	UDP_Add_Header(back_data,IAP_Cmd,IAP_Cmd_Send_Len,frameno);                                    //添加头部
	if((0 < IAPVarTypeStruct_Ptr->BlockSize)||(IAPVarTypeStruct_Ptr->BlockSize <= RUN_MAX_BLOCK))       	//IAP_VarEx.block_size
	{
		Ret = 0x01;
		back_data[IAP_Cmd_Send_State] = IAP_Ready; 					//升级就绪
		IAPVarTypeStruct_Ptr->IapState = IAPSTART;           		//升级开始
		IAPVarTypeStruct_Ptr->IapType = IAPTFTPWRITE;    			//升级类型为写
		
		IAPVarTypeStruct_Ptr->processing_tick = SysTick_1ms;
	}
	else
	{
		Ret = 0x02;
		back_data[IAP_Cmd_Send_State] = IAP_Error;
	}
	UDP_ADD_SoftwareVer(&back_data[IAP_Cmd_Send_SoftwareVer]); 		//添加固件版本
	
	NetCRC16(&back_data[0],IAP_Cmd_Send_Len);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , IP:%d.%d.%d.%d , port:%d\n",net_info.SocketId[0],ip[0],ip[1],ip[2],ip[3],port);
	
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);	//回复升级就绪
	
	return Ret;
}



/**
	* @name 云端升级命令 包括固件和配置
	* @para 
	*   data 下发数据包
	*   ip 目标ip
	*   port 目标端口号
	* @return 无
	*/
uint8_t UDP_CLOUD_IAP_Cmd(uint8_t* data,uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t back_data[CLOUD_IAP_Cmd_Send_Len]={0};
	uint16_t frameno = data[FRAME_NO_OFFSET] + (data[FRAME_NO_OFFSET+1]<<8);
	uint16_t FrameLen;      //帧总长度
	uint8_t Ret = 0x03;
	uint8_t buff[6];
	
	memset(buff,0,sizeof(buff));

	UINT32 sendlen = CLOUD_IAP_Cmd_Send_Len;
	
	if(DataLen <= CLOUD_IAP_Cmd_Rev_Filename)
	{
		return Ret;
	}

	memcpy(server_info.goal_ip, &data[CLOUD_IAP_Cmd_Rev_Ip], 4);
	IAPVarTypeStruct_Ptr->TFTP_Port = data[CLOUD_IAP_Cmd_Rev_Port] + (data[CLOUD_IAP_Cmd_Rev_Port+1]<<8);			//数据中的这个端口，目前并没有使用   2022-09-15
	sever_port = port;		//升级回复使用的端口，本来应该是使用上面数据中端口的
	
	memcpy(buff, ip, 4);
	buff[4] = port;
	buff[5] = port >> 8;
	SRAM_DMA_Write_Buff(buff, 6, SRAM_IAP_IP_ADDRESS);     //将配置工具的ip和port存入SRAM，回复升级结果时使用这个端口，而不是TFTP服务及文件传输的套接字
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"云端TFTP port:%04X , IP:%d.%d.%d.%d",IAPVarTypeStruct_Ptr->TFTP_Port,data[CLOUD_IAP_Cmd_Rev_Ip],data[CLOUD_IAP_Cmd_Rev_Ip+1],data[CLOUD_IAP_Cmd_Rev_Ip+2],data[CLOUD_IAP_Cmd_Rev_Ip+3]);

	FrameLen = data[FRAME_LEN_OFFSET] + (data[FRAME_LEN_OFFSET]<<8);
	
	IAPVarTypeStruct_Ptr->FtpFileNameLen = FrameLen - 42;                      //文件名长度
	
	if(IAPVarTypeStruct_Ptr->FtpFileNameLen > dat_buf_size)
	{
		return 0x02;
	}
	memcpy(IAPVarTypeStruct_Ptr->FtpFileName,&data[CLOUD_IAP_Cmd_Rev_Filename],IAPVarTypeStruct_Ptr->FtpFileNameLen);  //拷贝文件名
	
	if(data[CLOUD_IAP_Cmd_Rev_Filetype] == DATATYPE_IAP)                          //固件
	{
		IAPVarTypeStruct_Ptr->IapFileType = DATATYPE_IAP;//	
		UDP_ADD_SoftwareVer(&back_data[CLOUD_IAP_Cmd_Send_SoftwareVer]);         		      				   //添加固件版本
		back_data[CLOUD_IAP_Cmd_Send_Filetype] = DATATYPE_IAP; 
	}
	else if(data[CLOUD_IAP_Cmd_Rev_Filetype] == DATATYPE_CONFIG)                    //配置
	{
		IAPVarTypeStruct_Ptr->IapFileType = DATATYPE_CONFIG;
		UDP_ADD_SoftwareVer(&back_data[CLOUD_IAP_Cmd_Send_SoftwareVer]);  
		back_data[CLOUD_IAP_Cmd_Send_Filetype] = DATATYPE_CONFIG; 
	}
	else
	{
		return 0x02;
	}
	
	IAPVarTypeStruct_Ptr->BlockSize   = (data[CLOUD_IAP_Cmd_Rev_Block]) + (data[CLOUD_IAP_Cmd_Rev_Block+1]<<8); //IAP_VarEx.block_size
	
	IAPVarTypeStruct_Ptr->Md5[0]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 3];
	IAPVarTypeStruct_Ptr->Md5[1]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 2];
	IAPVarTypeStruct_Ptr->Md5[2]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 1];
	IAPVarTypeStruct_Ptr->Md5[3]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 0];
	
	IAPVarTypeStruct_Ptr->Md5[4]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 7];
	IAPVarTypeStruct_Ptr->Md5[5]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 6];
	IAPVarTypeStruct_Ptr->Md5[6]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 5];
	IAPVarTypeStruct_Ptr->Md5[7]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 4];
	
	IAPVarTypeStruct_Ptr->Md5[8]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 11];
	IAPVarTypeStruct_Ptr->Md5[9]      = data[CLOUD_IAP_Cmd_Rev_Md5 + 10];
	IAPVarTypeStruct_Ptr->Md5[10]     = data[CLOUD_IAP_Cmd_Rev_Md5 + 9];
	IAPVarTypeStruct_Ptr->Md5[11]     = data[CLOUD_IAP_Cmd_Rev_Md5 + 8];
	
	IAPVarTypeStruct_Ptr->Md5[12]     = data[CLOUD_IAP_Cmd_Rev_Md5 + 15];
	IAPVarTypeStruct_Ptr->Md5[13]     = data[CLOUD_IAP_Cmd_Rev_Md5 + 14];
	IAPVarTypeStruct_Ptr->Md5[14]     = data[CLOUD_IAP_Cmd_Rev_Md5 + 13];
	IAPVarTypeStruct_Ptr->Md5[15]     = data[CLOUD_IAP_Cmd_Rev_Md5 + 12];

	//处理要返回的数据帧
	UDP_Add_Header(back_data,data[CMD_OFFSET],CLOUD_IAP_Cmd_Send_Len,frameno);                   	//添加头部
	if((0 < IAPVarTypeStruct_Ptr->BlockSize)&&(IAPVarTypeStruct_Ptr->BlockSize <= RUN_MAX_BLOCK))
	{
		Ret = 0x01;
		back_data[CLOUD_IAP_Cmd_Send_State] = CLOUD_IAP_Ready;                                 		//升级就绪
		IAPVarTypeStruct_Ptr->IapState = IAPSTART;                                              	//升级开始
		IAPVarTypeStruct_Ptr->IapType = IAPTFTPREAD;                                           		//升级类型为读
		IAPVarTypeStruct_Ptr->TftpStart = TFTPREADSTART;                                          	//需要RCU主动发送文件读取命令  
	}
	else
	{
		Ret = 0x02;
		back_data[CLOUD_IAP_Cmd_Send_State] = CLOUD_IAP_Error;
	}

	NetCRC16(&back_data[0],CLOUD_IAP_Cmd_Send_Len);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , port:%x , len:%ld",net_info.SocketId[0],port,sendlen);
	
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);	//回复升级就绪
	return Ret;
}

/*******************************************************************************
* Function Name  : Udp_Internal_ReplyIAP
* Description    : UDP 网络升级完成回复
* Input          : None
* Output         : None
* Return         : 发送状态
*******************************************************************************/
uint8_t Udp_Internal_ReplyIAP(void)
{
	uint8_t back_data[IAP_Cmd_Send_Len]={0};
	uint16_t frameno = 0x8001;
	uint8_t R_IP[4] = {0};
	uint16_t R_Port = 0;
	UINT32 sendlen = IAP_Cmd_Send_Len;
	uint8_t rev = 0;
	
	SRAM_Read_Buff(R_IP,4,SRAM_IAP_IP_ADDRESS);
	R_Port |= SRAM_Read_Byte(SRAM_IAP_PORT_ADDRESS);
	R_Port |= SRAM_Read_Byte(SRAM_IAP_PORT_ADDRESS+1) << 8;

	sever_port = R_Port;                                     //无SRAM时测试用存储的端口，因为ip不会变
	
	//处理要返回的数据帧
	UDP_Add_Header(back_data,IAP_Cmd,IAP_Cmd_Send_Len,frameno);    	//添加头部
	back_data[IAP_Cmd_Send_State] = IAP_Finish; 					//升级就绪
	UDP_ADD_SoftwareVer(&back_data[IAP_Cmd_Send_SoftwareVer]); 		//添加固件版本
	
	NetCRC16(&back_data[0],IAP_Cmd_Send_Len);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , IP:%d.%d.%d.%d , port:%d",net_info.SocketId[0],R_IP[0],R_IP[1],R_IP[2],R_IP[3],R_Port);
	
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, R_IP, R_Port);	//回复升级就绪
	return rev;
}

/*******************************************************************************
* Function Name  : Udp_Internal_ReplyIAP
* Description    : UDP 网络升级完成回复
* Input          : None
* Output         : None
* Return         : 发送状态
*******************************************************************************/
uint8_t Cloud_Internal_ReplyIAP(void)
{
	uint8_t rev = 0;
	uint8_t back_data[CLOUD_IAP_Cmd_Send_Len]={0};
	uint16_t frameno = 0x8001;
	
	uint8_t R_IP[4] = {0};
	uint16_t R_Port = 0;
	UINT32 sendlen = IAP_Cmd_Send_Len + 1;
	
	SRAM_Read_Buff(R_IP,4,SRAM_IAP_IP_ADDRESS);
	R_Port |= SRAM_Read_Byte(SRAM_IAP_PORT_ADDRESS);
	R_Port |= SRAM_Read_Byte(SRAM_IAP_PORT_ADDRESS+1) << 8;
	
	//处理要返回的数据帧
	UDP_Add_Header(back_data,CLOUD_IAP_Cmd,CLOUD_IAP_Cmd_Send_Len,frameno);              							 //0xfffe添加头部
	back_data[CLOUD_IAP_Cmd_Send_State] = IAP_Finish;                                             	 //升级就绪
	UDP_ADD_SoftwareVer(&back_data[CLOUD_IAP_Cmd_Send_SoftwareVer]);         		      				   //添加固件版本
	back_data[CLOUD_IAP_Cmd_Send_Filetype] = DATATYPE_IAP;
	NetCRC16(&back_data[0],CLOUD_IAP_Cmd_Send_Len);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , IP:%d.%d.%d.%d , port:%d",net_info.SocketId[0],R_IP[0],R_IP[1],R_IP[2],R_IP[3],R_Port);
	
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, R_IP, R_Port);	//回复升级就绪
	return rev;
}

/**
  * @name  		主机向服务器发送注册函数
  * @param    	无
  * @retval 	无
  * @brief          
  */
void UDP_Search_Ack(void)
{
	
	UINT32 sendlen = Search_Cmd_Send_Len+44;
	uint8_t rev = 0;
	
	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	//处理要返回的数据帧
	UDP_Add_Header(Global_Large_Buff,Search_Cmd,sendlen,0xffff);    				//添加头部
	UDP_Add_Subnet(&Global_Large_Buff[Search_Cmd_Send_Subnet]);                 	//添加子网掩码
	UDP_Add_Gateway(&Global_Large_Buff[Search_Cmd_Send_Gateway]);    				//添加网关
	UDP_Add_Port(&Global_Large_Buff[Search_Cmd_Send_Port]);                  		//添加RCU端口     							 
	UDP_Add_Mac(&Global_Large_Buff[Search_Cmd_Send_Mac]);                        	//添加Mac
	UDP_ADD_SoftwareVer(&Global_Large_Buff[Search_Cmd_Send_SoftwareVer]);        	//添加固件版本
	UDP_ADD_ConfigVer(&Global_Large_Buff[Search_Cmd_Send_ConfigVer]);            	//添加配置版本
	
	Global_Large_Buff[Search_Cmd_Send_ConfigVer+3] = DNS_SERVER_IP[0];
	Global_Large_Buff[Search_Cmd_Send_ConfigVer+4] = DNS_SERVER_IP[1];
	Global_Large_Buff[Search_Cmd_Send_ConfigVer+5] = DNS_SERVER_IP[2];
	Global_Large_Buff[Search_Cmd_Send_ConfigVer+6] = DNS_SERVER_IP[3];
	SRAM_Read_Buff(&Global_Large_Buff[Search_Cmd_Send_ConfigVer+7],16,SRAM_Register_Start_ADDRESS + Register_RoomTypeNote_OFFSET);
	SRAM_Read_Buff(&Global_Large_Buff[Search_Cmd_Send_ConfigVer+23],16,SRAM_Register_Start_ADDRESS + Register_RoomNumNote_OFFSET);
	SRAM_Read_Buff(&Global_Large_Buff[Search_Cmd_Send_ConfigVer+39],4,SRAM_Register_Start_ADDRESS + Register_HouseType_OFFSET);
	SRAM_Read_Buff(&Global_Large_Buff[Search_Cmd_Send_ConfigVer+43],4,SRAM_Register_Start_ADDRESS + Register_RoomNumber_OFFSET);
	
	NetCRC16(&Global_Large_Buff[0],sendlen);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , IP:%d.%d.%d.%d , port:%d",net_info.SocketId[0],server_info.dis_ip[0],server_info.dis_ip[1],server_info.dis_ip[2],server_info.dis_ip[3],server_info.dis_port);
	
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &Global_Large_Buff[0], &sendlen, server_info.dis_ip, server_info.dis_port);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s rev:%d",__func__,rev);
	
	LOG_NET_COMM_Send_Record(0x01,server_info.dis_ip,server_info.dis_port,&Global_Large_Buff[0],sendlen);
}

/**
  * @name  			心跳包主动上报函数
  * @param          无
  * @retval 		无
  * @brief          不需要回复的心跳包发送函数占少数
  * @attention       心跳包每10秒调用一次
  */
void UDP_Heart_Send(void)
{
	UINT32 sendlen = 0x00;
	
	if((server_info.frame_no < 0xfffe) && (server_info.frame_no >= 0x8000))      
	{
		server_info.frame_no++;
	}else{
		server_info.frame_no = 0x8000;
	}
	
	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	sendlen = HEAD_LEN;
	//2025-9-25 修改心跳包参数内容 
	Global_Large_Buff[sendlen++] = MACAddr[0];		
	Global_Large_Buff[sendlen++] = MACAddr[1];		
	Global_Large_Buff[sendlen++] = MACAddr[2];		
	Global_Large_Buff[sendlen++] = MACAddr[3];		
	
	Global_Large_Buff[sendlen++] = MACAddr[4];		
	Global_Large_Buff[sendlen++] = MACAddr[5];		

	sendlen += 0x06;


	sendlen += 0x02;	//添加CRC校验长度
	UDP_Add_Header(Global_Large_Buff,Heart_Cmd,sendlen,server_info.frame_no);	//添加头部	


	NetCRC16(&Global_Large_Buff[0],sendlen);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s..",__func__);
	
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &Global_Large_Buff[0], &sendlen, server_info.dis_ip, server_info.dis_port);
	LOG_NET_COMM_Send_Record(0x01,server_info.dis_ip,server_info.dis_port,&Global_Large_Buff[0],sendlen);

}

/*******************************************************************************
* Function Name  : Udp_Internal_QueryTFTPIP_CMD
* Description    : 向服务器获取TFTP日志服务器IP
*******************************************************************************/
void Udp_Internal_QueryTFTPIP_CMD(void)
{
	UINT32 sendlen = HEAD_LEN + 2;

	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s",__func__);
	
	if((server_info.frame_no < 0xfffe) && (server_info.frame_no >= 0x8000))      
	{
		server_info.frame_no++;
	}
	else
	{
		server_info.frame_no = 0x8000;
	}
	
	memcpy(&Global_Large_Buff[HEAD_LEN],tftp_log.DomainName,tftp_log.DN_Lens);
	sendlen += tftp_log.DN_Lens;
	
	UDP_Add_Header(Global_Large_Buff,In_BLVQueryTFTPIP_CMD,sendlen,server_info.frame_no);
	NetCRC16(&Global_Large_Buff[0],sendlen);

	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &Global_Large_Buff[0], &sendlen, server_info.dis_ip, server_info.dis_port);
	
	LOG_NET_COMM_Send_Record(0x01,server_info.dis_ip,server_info.dis_port,&Global_Large_Buff[0],sendlen);
}


/*******************************************************************************
* Function Name  : Udp_Internal_DayTimeSet_Process
* Description    : 服务器下发设置白天时间范围
*******************************************************************************/
uint8_t Udp_Internal_DayTimeSet_Process(uint8_t *data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	/*CRC校验*/
	uint16_t frame_id = 0;
	UINT32 len = HEAD_LEN + 3;
	
	uint8_t back_data[20];
	memset(back_data,0,sizeof(back_data));
	
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	DevActionGlobal.DayStart = data[HEAD_LEN];     //白天起始时间   
	DevActionGlobal.DayEnd = data[HEAD_LEN+1];       //白天结束时间   
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"服务器设置白天起始时间:%d 结束时间:%d",DevActionGlobal.DayStart,DevActionGlobal.DayEnd);   

	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	
	UDP_Add_Header(back_data,In_BLVDayNightTimeSet_Cmd,len,frame_id);
	NetCRC16(back_data,len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0],back_data,&len,ip,port);

	return 0;
}

/*******************************************************************************
* Function Name  : Udp_Internal_QueryTFTPIP_Process
* Description    : 向服务器获取TFTP服务器IP
*******************************************************************************/
uint8_t Udp_Internal_QueryTFTPIP_Process(uint8_t *data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{	
	/*CRC校验*/
	uint16_t frame_id = 0;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	
	//Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_QueryTFTPIP_Process,CRC:%4X - %4X",data_crc,NetCRC16_2(data,DataLen-2));
	
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	server_info.tftp_ip[0] = data[HEAD_LEN];
	server_info.tftp_ip[1] = data[HEAD_LEN+1];
	server_info.tftp_ip[2] = data[HEAD_LEN+2];
	server_info.tftp_ip[3] = data[HEAD_LEN+3];
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"下发TFTP服务器IP：%d.%d.%d.%d",data[HEAD_LEN], data[HEAD_LEN+1],data[HEAD_LEN+2],data[HEAD_LEN+3]); 
	
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;

	Udp_Internal_Process_Ack(In_BLVQueryTFTPIP_CMD,frame_id,ip,port);
	
	return 0;
}

/*******************************************************************************
* Function Name  : Udp_Internal_TFTPDNSet_Process
* Description    : TFTP日志服务器域名设置
*******************************************************************************/
uint8_t Udp_Internal_TFTPDNSet_Process(uint8_t *data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	UINT32 len = HEAD_LEN+3;
	uint8_t senddata[20];
	uint16_t tftp_port = 0x00;
	uint16_t tftp_time = 0x00;
	memset(senddata,0,sizeof(senddata));
	
	/*CRC校验*/
	uint16_t frame_id = 0;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	
	if((NetCRC16_2(data,DataLen-2) != data_crc) || (DataLen > 276)) 
	{
		return 0xF0;
	}
	
	tftp_port = data[HEAD_LEN + 1];
	tftp_port |= data[HEAD_LEN + 2] << 8;
	
	tftp_time = data[HEAD_LEN + 3];
	tftp_time |= data[HEAD_LEN + 4] << 8;
	
	if((data[HEAD_LEN + 5] != 0x00) && (tftp_port != 0x00))
	{
		SYS_Log_Switch = data[HEAD_LEN];
		SRAM_Write_DW(SYS_Log_Switch,SRAM_Register_Start_ADDRESS + Register_TFTPStatus_OFFSET);

		tftp_log.Port = tftp_port;
		tftp_log.Time = tftp_time;

		tftp_log.DN_Lens = data[HEAD_LEN + 5];
		memcpy(tftp_log.DomainName,&data[HEAD_LEN + 6],tftp_log.DN_Lens);
		SRAM_Write_Buff((uint8_t*)&tftp_log,sizeof(TFTP_LOG),(SRAM_Register_Start_ADDRESS+Register_TFTPLOGPort_OFFSET));
		
		SRAM_Write_DW(0x00,SRAM_Register_Start_ADDRESS + Register_TFTPUploadTime_OFFSET);
		
		Retain_Flash_Register_Data();
		
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"tftp log swicth state:%4X port:%d time:%d",SYS_Log_Switch,tftp_log.Port,tftp_log.Time);
		Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"Tftp DomainName:",(uint8_t *)tftp_log.DomainName,tftp_log.DN_Lens);
	}
	
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	UDP_Add_Header(senddata,In_BLVTFTPDomainName_Cmd,len,frame_id);
	NetCRC16(senddata,len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0],senddata,&len,ip,port);
	
	return 0;
}



/*******************************************************************************
* Function Name  : Udp_Internal_TFTPData_Read_Process
* Description    : TFTP日志服务器信息读取
*******************************************************************************/
uint8_t Udp_Internal_TFTPData_Read_Process(uint8_t *data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	UINT32 len = HEAD_LEN + 8;

	uint16_t tftp_time = 0x00;
	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	/*CRC校验*/
	uint16_t frame_id = 0;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	
	//Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_TFTPData_Read_Process,CRC:%4X - %4X",data_crc,NetCRC16_2(data,DataLen-2));
	
	if((NetCRC16_2(data,DataLen-2) != data_crc) || (DataLen > 276)) 
	{
		return 0xF0;
	}
	
	Global_Large_Buff[HEAD_LEN] = SYS_Log_Switch;                     //日志开启状态
	Global_Large_Buff[HEAD_LEN + 1] = (tftp_log.Port & 0xff);         //tftp_port_L
	Global_Large_Buff[HEAD_LEN + 2] = ((tftp_log.Port >>8 ) & 0xff);  //tftp_port_H
	
	if(tftp_log.Time > SRAM_Read_DW(SRAM_Register_Start_ADDRESS + Register_TFTPUploadTime_OFFSET))
	{
		tftp_time = tftp_log.Time - SRAM_Read_DW(SRAM_Register_Start_ADDRESS + Register_TFTPUploadTime_OFFSET);
	}
	else
	{
		tftp_time = 0x00;
	}
	Global_Large_Buff[HEAD_LEN + 3] = (tftp_time & 0xff);            //tftp log_time_L
	Global_Large_Buff[HEAD_LEN + 4] = ((tftp_time >>8) & 0xff);      //tftp log_time_H
	
	Global_Large_Buff[HEAD_LEN + 5] = tftp_log.DN_Lens;              //tftp Dm_lens
	
	memcpy(&Global_Large_Buff[HEAD_LEN + 6],tftp_log.DomainName,tftp_log.DN_Lens);
	
	len += tftp_log.DN_Lens;
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"tftp log swicth state:%4X port:%d time:%d",SYS_Log_Switch,tftp_log.Port,tftp_log.Time);
	Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"Tftp DomainName:",(uint8_t *)tftp_log.DomainName,tftp_log.DN_Lens);
	
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	UDP_Add_Header(Global_Large_Buff,In_BLVTFTPDataRead_Cmd,len,frame_id);
	NetCRC16(Global_Large_Buff,len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0],Global_Large_Buff,&len,ip,port);
	
	return 0;
}


/**
	* @name 普通控制指令状态回复
	* @para
	*   cmd 命令号
	*   frame_no 帧号
	*   ip  目标ip地址
	*   port 目标端口号
	*/
uint8_t Udp_Internal_Process_Ack(uint8_t cmd,uint16_t frame_no,uint8_t *ip,uint16_t port)
{
	uint8_t rev=0;
	UINT32 len = HEAD_LEN+2;
	uint8_t senddata[20];
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s\n",__func__);
	
	UDP_Add_Header(senddata,cmd,len,frame_no);
	NetCRC16(senddata,len);
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0],senddata,&len,ip,port);
	return rev;
}

/**
	* @name 本地对于服务器搜索命令的回复
	* @para 
	*   data 下发的数据包  
	*   len  长度
	* @return 无
  * @attention  两种命令均为1的报文，1，搜索命令 长度为28字节   一般用于局域网搜索
  *                                  2，注册回复命令 长度为17个字节，就是头加校验   一般用于服务器
	*/
uint8_t Udp_Internal_Search(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t back_data[Search_Cmd_Send_Len]={0};
	uint16_t search_rxno = 0;                  //搜索的帧号，如果是0xffff，就是主机在云端注册成功
	uint16_t src_port;  
	uint8_t Ret = 0x03;
	
	if((DataLen != Search_Cmd_EnSure_Rev_Len)&&(DataLen != Search_Cmd_Rev_Len))
	{
		return Ret;
	}
	
	search_rxno = data[FRAME_NO_OFFSET]+data[FRAME_NO_OFFSET+1]*256;   //唯一的帧号赋值

	switch(DataLen)
	{
		case Search_Cmd_EnSure_Rev_Len:
			{
				//uint8_t SendData[Heart_Cmd_Send_Len];
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"注册命令回复！");
				
				server_info.udp_sta = 0x02;
				
				server_info.active_cmd_flag |= UDP_ActSend_TimeSync_Flag;		//注册成功后，向服务器获取时间
				server_info.active_cmd_flag |= UDP_ActSend_RoomState_Flag;		//注册成功后，向服务器获取房态
				
				server_info.register_flag = 0x00;
				server_info.register_num = 0x00;
				server_info.register_tick = SysTick_1s;
				server_info.udp_timesync_cnt = 0x00;
				server_info.udp_periodic_cnt = 0x00;
				server_info.udp_online_tick = SysTick_1ms;
	
				if(0xffff == search_rxno)    //云端服务器发过来的帧号
				{
//					server_info.RCUServer = RCU_CLOUD_SERVER;      //云端服务器已注册
					LOG_SYS_Server_Comm_State_Record(RCU_CLOUD_SERVER);
					server_info.online_state = 3;               //2023-10-07
				}
				else
				{
//					server_info.RCUServer = RCU_LOCAL_SERVER;      //本地
					LOG_SYS_Server_Comm_State_Record(RCU_LOCAL_SERVER);
					server_info.online_state = 2;               //2023-10-07
				}
				
				
				//2025-10-10 取消接收到注册命令后，继续发送心跳包命令
//				UDP_Add_Header(SendData,Heart_Cmd,Heart_Cmd_Send_Len,0xffff);//0xffff              								 //添加头部
//				NetCRC16(&SendData[0],Heart_Cmd_Send_Len);
//				UINT32 sendlen = Heart_Cmd_Send_Len;
//				CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &SendData[0], &sendlen,server_info.dis_ip, server_info.dis_port);//向服务器发数据	//发送心跳包
				
			}
			break;
		case Search_Cmd_Rev_Len:
			if(search_rxno >= 0x8000)	 //帧号或长度不对就返回
			{
				return 0x02;
			}	
			
			src_port = data[Search_Cmd_Rev_ClientPort] + (data[Search_Cmd_Rev_ClientPort+1]<<8);	
			
			if(0x01 == data[Search_Cmd_Rev_ClientIf]) //检查是否是服务器
			{
				/*对比本地保存的服务器地址，不对的话便保存起来*/
				if((data[Search_Cmd_Rev_ClientIp] != server_info.dis_ip[0]) 
					|| (data[Search_Cmd_Rev_ClientIp+1] != server_info.dis_ip[1])
					|| (data[Search_Cmd_Rev_ClientIp+2] != server_info.dis_ip[2])
					|| (data[Search_Cmd_Rev_ClientIp+3] != server_info.dis_ip[3])
					|| (src_port != server_info.dis_port))
				{
					server_info.dis_port = src_port;
					server_info.dis_ip[0] = data[Search_Cmd_Rev_ClientIp];
					server_info.dis_ip[1] = data[Search_Cmd_Rev_ClientIp+1];
					server_info.dis_ip[2] = data[Search_Cmd_Rev_ClientIp+2];
					server_info.dis_ip[3] = data[Search_Cmd_Rev_ClientIp+3];
				}
			}
			
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"收到搜索命令！");
			
			//处理要返回的数据帧  
			UDP_Add_Header(back_data,Search_Cmd,Search_Cmd_Send_Len,0xffff);            	//添加头部
			UDP_Add_ServerIp(&back_data[Search_Cmd_Rev_UserCode]);                         	//将此四个字节的用户码改成服务器IP地址
			
			UDP_Add_Subnet(&back_data[Search_Cmd_Send_Subnet]);                 			//添加子网掩码
			UDP_Add_Gateway(&back_data[Search_Cmd_Send_Gateway]);               			//添加网关
			UDP_Add_Mac(&back_data[Search_Cmd_Send_Mac]);                          			//添加Mac
			UDP_Add_Port(&back_data[Search_Cmd_Send_Port]);                       			//添加RCU端口
			UDP_ADD_SoftwareVer(&back_data[Search_Cmd_Send_SoftwareVer]);         			//添加固件版本
			UDP_ADD_ConfigVer(&back_data[Search_Cmd_Send_ConfigVer]);             			//添加配置版本

			NetCRC16(&back_data[0],Search_Cmd_Send_Len);
			UINT32 sendlen = Search_Cmd_Send_Len;
			CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);    //SOCK_UDPS,
			break;
	}

	return 0x01;
}


/*************************
**函数名：Udp_Internal_PC_Testing_Reply
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：UDP网络PC测试设备输入输出回复
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_PC_Testing_Reply(uint8_t *reply_data,uint16_t reply_len,uint16_t pack_frame,uint8_t *ip,uint16_t port)
{
	UINT32 back_len = HEAD_LEN + reply_len + 3;
	
	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	
	UDP_Add_Header(Global_Large_Buff,In_BLVPCTestDevice_Cmd,back_len,pack_frame);            	//添加头部
	
	for(uint16_t i=0;i<reply_len;i++)
	{
		Global_Large_Buff[HEAD_LEN+i] = reply_data[i];
	}
	
	NetCRC16(&Global_Large_Buff[0],back_len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &Global_Large_Buff[0], &back_len, ip, port);    //SOCK_UDPS,
	
	return 0x00;
}

/*************************
**函数名：Udp_Internal_PC_Testing_Reply
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：UDP网络PC测试设备输入输出上报
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_PC_Testing_Reported(uint8_t *reply_data,uint16_t reply_len,uint8_t *ip,uint16_t port)
{
	UINT32 back_len = HEAD_LEN + reply_len + 2;

	Dbg_Println(DBG_OPT_DEVICE_STATUS,"%s",__func__);
	
	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	if((server_info.frame_no < 0xfffe) && (server_info.frame_no >= 0x8000))      
	{
		server_info.frame_no++;
	}
	else
	{
		server_info.frame_no = 0x8000;
	}
	
	UDP_Add_Header(Global_Large_Buff,In_BLVPCTestDevice_Cmd,back_len,server_info.frame_no);            	//添加头部
	
	for(uint16_t i=0;i<reply_len;i++)
	{
		Global_Large_Buff[HEAD_LEN+i] = reply_data[i];
	}
	
	NetCRC16(&Global_Large_Buff[0],back_len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &Global_Large_Buff[0], &back_len, ip, port);    //SOCK_UDPS,
	
	return 0x00;
}

/*************************
**函数名：Udp_Internal_PC_Testing_DataDeal
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：UDP下发设备输入输出测试数据处理
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_PC_Testing_DataDeal(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t control_dev = 0,control_addr = 0,control_cmd = 0,temp = 0,temp1 = 0,temp2 = 0;
	uint32_t device_listaddr = 0;
	uint16_t ack_frame = 0;
	uint8_t back_data[15];
	uint8_t control_num = 0;
	
	memset(back_data,0,15);
	
	ack_frame = data[FRAME_NO_OFFSET] + (data[FRAME_NO_OFFSET+1]<<8);   //帧号
	 
	control_dev = data[HEAD_LEN+1];		//控制设备类型
	control_addr = data[HEAD_LEN+2];		//控制设备地址
	
	g_pc_test.pc_ip[0] = ip[0];
	g_pc_test.pc_ip[1] = ip[1];
	g_pc_test.pc_ip[2] = ip[2];
	g_pc_test.pc_ip[3] = ip[3];
	g_pc_test.pc_port = port;
	
	/*记录一下当前测试的设备类型及设备地址*/
	g_pc_test.test_dev = control_dev;
	g_pc_test.test_addr = control_addr;
	
	device_listaddr = Find_Device_List_Information(control_dev,control_addr);
	if((device_listaddr < SRAM_Device_List_Start_Addr) || (device_listaddr > SRAM_Device_List_End_Addr))	return 0xF0;
	
	switch(control_dev)
	{
		case DEV_C5IO_Type:		//C5IO 数据处理
			control_cmd = data[HEAD_LEN+3];
			if(control_cmd == BLV_C5IO_Set_Relay_CMD)		//继电器控制
			{
				control_num = DataLen - HEAD_LEN - 2 - 4;
				
				if(control_num >= 6)	control_num = 6;	//目前最长6Byte的控制数据
				//Dbg_Println(DBG_OPT_DEVICE_STATUS,"NET PC Test C5IO_Control Len %d,Control_NUM:%d",DataLen,control_num);
				
				for(uint8_t i = 0;i<control_num;i++)
				{
					temp = data[HEAD_LEN + 4 + i];
					for(uint8_t j = 0;j<4;j++)
					{
						temp2 = i*4+j;					//控制回路
						temp1 = (temp >> j*2) & 0x03;	//控制状态
						if(temp1 != 0x00)	
						{
							//Dbg_Println(DBG_BIT_NET_STATUS_bit,"PC Test C5IO_Control_RelayCH%d status:%d",temp2,temp1);
							#ifndef BLV_TEST_EN
							{
								UINT8 control[6];
								control[0] = Dev_Host_HVout;
								control[1] = 0x00;
								control[2] = temp2;  //回路
								control[3] = 0x00;
								control[4] = temp1;  //控制状态
								control[5] = 0x00;
								
								DevActionCtrl(control, 6);			//继电器
							}
							#else
							BUS_C5IO_Control_Relay(device_listaddr,temp2,temp1);	//楼下生产测试使用
							#endif
							
						}
					}
				}
			}else if(control_cmd == BLV_C5IO_Set_Do_CMD)	//DO控制
			{
				for(uint8_t i = 0;i<2;i++)
				{
					temp = data[HEAD_LEN + 4 + i];
					for(uint8_t j = 0;j<4;j++)
					{
						temp2 = i*4+j;					//控制回路
						temp1 = (temp >> j*2) & 0x03;	//控制状态
						if(temp1 != 0x00)	
						{
							//Dbg_Println(DBG_BIT_Debug_STATUS_bit,"PC Test C5IO_Control_DoCH%d status:%d",temp2,temp1);
							BUS_C5IO_Control_Do(device_listaddr,temp2,temp1);
						}
					}
				}
			}
			return 0x00;
		case DEV_C5MUSIC_Type:
			control_cmd = data[HEAD_LEN + 3];
			if(control_cmd == BLV_C5MUSIC_Specify_Play_CMD)
			{
				temp = data[HEAD_LEN + 4];	//播放状态
				temp1 = data[HEAD_LEN + 5];	//播放文件夹
				temp2 = data[HEAD_LEN + 6];	//播放ID
				
				//Dbg_Println(DBG_BIT_NET_STATUS_bit,"PC Test C5Music_Control dir:%d id:%d status:%d",temp1,temp2,temp);
				BUS_C5MUSIC_Playback(device_listaddr,temp1,temp,temp2);
			}
			
			{
				/*回复数据打包*/
				uint8_t ack_buff[4] = {0};
				
				ack_buff[0] = g_pc_test.test_flag;
				ack_buff[1] = g_pc_test.test_dev;
				ack_buff[2] = g_pc_test.test_addr;
				ack_buff[3] = 0x01;					//执行结果
				
				Udp_Internal_PC_Testing_Reply(ack_buff,0x04,ack_frame,g_pc_test.pc_ip,g_pc_test.pc_port);
			}
			break;
		case DEV_RS485_PWM:

				control_cmd = data[HEAD_LEN + 3];
				if(control_cmd == C12_SET_LIGHT_CMD)
				{
					temp = data[HEAD_LEN + 4];	//设置回路
					temp1 = data[HEAD_LEN + 5];	//亮度值
					temp2 = data[HEAD_LEN + 6];	//渐变时间
					
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"PC Test C12Dimming:%d light:%d fade:%d",temp1,temp2,temp);

					if(temp)
					{
						UINT8 control[6];
						control[0] = DEV_RS485_PWM;
						control[1] = 0x00;
						control[2] = temp-1;  //回路
						control[3] = 0x00;
						control[4] = 0x01;  //控制状态
						control[5] = temp1;  //亮度值
						DevActionCtrl(control, 6);			//继电器
					}

				}
			break;
		default: break;
	}
	
	
	return 0x00;
}

/*************************
**函数名：Udp_Internal_BLVPCTestDevice_Process
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：BLV-C1PC下发设备输入输出测试数据处理
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_BLVPCTestDevice_Process(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	/*CRC校验*/
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	uint8_t temp1 = 0;
	uint32_t dev_addr = 0;
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s",__func__);
	
	dev_addr = Find_Device_List_Information(DEV_PCTEST_TYPE,DEV_PCTEST_Addr);
	
	Device_Public_Information_G BUS_Public;
	PC_TEST_DEVICE_INFO PC_Test_Info;
	
	
	SRAM_DMA_Read_Buff((uint8_t *)&BUS_Public,sizeof(Device_Public_Information_G),dev_addr);		
	SRAM_DMA_Read_Buff((uint8_t *)&PC_Test_Info,sizeof(PC_TEST_DEVICE_INFO),dev_addr+Dev_Privately);
	
	/*测试数据内容*/
	temp1 = data[HEAD_LEN];
	if(temp1 == 0x01)			//测试输入 - 同时检测时间
	{
		g_pc_test.test_flag = 0x11;		
		
		g_pc_test.test_dev = data[HEAD_LEN + 1];			//输入检测设备类型
		g_pc_test.test_addr = data[HEAD_LEN + 2];			//输入检测设备地址
		PC_Test_Info.test_time = data[HEAD_LEN + 3];		//测试时间，单位：分钟
		
		PC_Test_Info.test_flag = g_pc_test.test_flag;
		PC_Test_Info.test_tick = SysTick_1ms;
		PC_Test_Info.test_time *= 60000;
		
		g_pc_test.pc_ip[0] = ip[0];			//2022-07-12
		g_pc_test.pc_ip[1] = ip[1];
		g_pc_test.pc_ip[2] = ip[2];
		g_pc_test.pc_ip[3] = ip[3];
		g_pc_test.pc_port = port;
	}
	else if(temp1 == 0x02)		//测试输出
	{
		g_pc_test.test_flag = 0x12;		
		PC_Test_Info.test_flag = g_pc_test.test_flag;
		PC_Test_Info.test_tick = SysTick_1ms;
		PC_Test_Info.test_time = 120000;
	
		Udp_Internal_PC_Testing_DataDeal(data,DataLen,ip,port);		
	}else if(temp1 == 0x03)		//开启巡回测试 - 测试485端口
	{
		g_pc_test.test_flag = 0x13;		
		PC_Test_Info.test_flag = g_pc_test.test_flag;
		g_pc_test.tour_num = 0;
		g_pc_test.tour_succ = 0;
		
		
		g_pc_test.pc_ip[0] = ip[0];
		g_pc_test.pc_ip[1] = ip[1];
		g_pc_test.pc_ip[2] = ip[2];
		g_pc_test.pc_ip[3] = ip[3];
		g_pc_test.pc_port = port;
	}
	
	BUS_Public.check = 0x00;
	BUS_Public.check = DoubleData_CheckSum((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), (uint8_t *)&PC_Test_Info, sizeof(PC_TEST_DEVICE_INFO));
	SRAM_DMA_Write_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G),dev_addr);/*将数据保存*/
	SRAM_DMA_Write_Buff((uint8_t *)&PC_Test_Info,sizeof(PC_TEST_DEVICE_INFO),dev_addr+Dev_Privately);
			
	
	return 0x00;
}



/*************************
**函数名：UDP_Conversion_Baud
**参  数：data：接受到的数据
**作  用：将数据转换为对应的波特率
**返回值：对应的波特率
************************/
uint32_t UDP_Conversion_Baud(uint8_t data)
{
	uint32_t baud = 0;
	switch(data)
	{
		case 0x01:
			baud = 9600;
			break;
		case 0x02:
			baud = 14400;
			break;
		case 0x03:
			baud = 19200;
			break;
		case 0x04:
			baud = 38400;
			break;
		case 0x05:
			baud = 56000;
			break;
		case 0x06:
			baud = 57600;
			break;
		case 0x07:
			baud = 115200;
			break;
	}
	return baud;
}

/*************************
**函数名：UDP_Conversion_Baud
**参  数：data：接受到的数据
**作  用：将数据转换为对应的波特率
**返回值：对应的波特率
************************/
uint8_t UDP_Baud_Conversion_Data(uint32_t data)
{
	uint8_t re_data = 0;
	switch(data)
	{
		case 9600:
			re_data = 0x01;
			break;
		case 14400:
			re_data = 0x02;
			break;
		case 19200:
			re_data = 0x03;
			break;
		case 38400:
			re_data = 0x04;
			break;
		case 56000:
			re_data = 0x05;
			break;
		case 57600:
			re_data = 0x06;
			break;
		case 115200:
			re_data = 0x07;
			break;
	}
	return re_data;
}

/*************************
**函数名：Udp_Internal_SeriaNet_Process
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：BLV-C1透传数据设置数据处理
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_SeriaNet_Process(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	/*CRC校验*/
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	uint8_t back_data[SeriaNet_Cmd_Send_Len]={0};
	UINT32 sendlen = SeriaNet_Cmd_Send_Len;
	uint8_t temp = 0;
	uint16_t pack_frame = 0,temp_len = 0;
	
	pack_frame = data[FRAME_NO_OFFSET] + (data[FRAME_NO_OFFSET+1]<<8);   //帧号
	
	SRAM_DMA_Write_Buff(ip,4,SRAM_IAP_IP_ADDRESS);			//保存PC IP地址
	SRAM_Write_Word(port,SRAM_IAP_PORT_ADDRESS);			//保存PC 端口号
	/*接收到透传设置命令*/
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s IP:%02X.%02X.%02X.%02X Port:%d\r\n",__func__,ip[0],ip[1],ip[2],ip[3],port);
	
	/*透传设置处理*/
	temp = data[HEAD_LEN];
	switch(temp)
	{
		case 0x01:	//透传状态查询 - 立即回复
			UDP_Add_Header(back_data,In_SeriaNet_Cmd,SeriaNet_Cmd_Send_Len,pack_frame);            	//添加头部
			back_data[HEAD_LEN] = 0x01;
			
			if(data[HEAD_LEN+1] == 0x01)			//端口1
			{	
				back_data[HEAD_LEN+1] = Poll485_Info.port_mode;
				Poll485_Info.mode_tick = SysTick_1s;
			}else if(data[HEAD_LEN+1] == 0x02)		//端口2
			{
				back_data[HEAD_LEN+1] = Act485_Info.port_mode;
				Act485_Info.mode_tick = SysTick_1s;
			}else if(data[HEAD_LEN+1] == 0x03)		//端口3
			{
				back_data[HEAD_LEN+1] = BUS485_Info.port_mode;
				BUS485_Info.mode_tick = SysTick_1s;
			}
			
			NetCRC16(&back_data[0],SeriaNet_Cmd_Send_Len);
			CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);   
			break;
		case 0x02:	//透传设置 - 立即回复
			UDP_Add_Header(back_data,In_SeriaNet_Cmd,SeriaNet_Cmd_Send_Len,pack_frame);            	//添加头部
			back_data[HEAD_LEN] = 0x02;
			back_data[HEAD_LEN+1] = 0x01;
		
			if(data[HEAD_LEN+1] == 0x01)			//端口1
			{
				Poll485_Info.baud = UDP_Conversion_Baud(data[HEAD_LEN+2]);		//设置的波特率
				if(Poll485_Info.baud != Polling_Baud)		//设置波特率
				{
					Poll485_Info.BaudRateCfg(Poll485_Info.baud);
				}
				Poll485_Info.mode_outtime = data[HEAD_LEN+3]*2;					//设置模式超时时间
				Poll485_Info.port_mode = data[HEAD_LEN+4];						//设置端口模式
				Poll485_Info.mode_tick = SysTick_1s;
			}else if(data[HEAD_LEN+1] == 0x02)		//端口2
			{
				Act485_Info.baud = UDP_Conversion_Baud(data[HEAD_LEN+2]);		//设置的波特率
				if(Act485_Info.baud != Active_Baud)			//设置波特率
				{
					Act485_Info.BaudRateCfg(Act485_Info.baud);
				}
				Act485_Info.mode_outtime = data[HEAD_LEN+3]*2;					//设置模式超时时间
				Act485_Info.port_mode = data[HEAD_LEN+4];						//设置端口模式
				Act485_Info.mode_tick = SysTick_1s;
				
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"Act485_Info.baud:%d",Act485_Info.baud );
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"Act485_Info.pass_outtime:%d",Act485_Info.mode_outtime );
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"Act485_Info.port_mode:%d",Act485_Info.port_mode );
			}else if(data[HEAD_LEN+1] == 0x03)		//端口3
			{
				BUS485_Info.baud = UDP_Conversion_Baud(data[HEAD_LEN+2]);		//设置的波特率
				if(BUS485_Info.baud != Bus_Baud)			//设置波特率
				{
					
				}
				BUS485_Info.mode_outtime = data[HEAD_LEN+3]*2;					//设置模式超时时间
				BUS485_Info.port_mode = data[HEAD_LEN+4];						//设置端口模式
				BUS485_Info.mode_tick = SysTick_1s;
			}else {
				back_data[HEAD_LEN+1] = 0x02;
			}
			
			NetCRC16(&back_data[0],SeriaNet_Cmd_Send_Len);
			CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);   
			break;
		case 0x03:	//透传数据传输 - 设备回复或设备没回复，主机回复
			
			
			if(data[HEAD_LEN+1] == 0x01)
			{
				Poll485_Info.mode_tick = SysTick_1s;
			}else if(data[HEAD_LEN+1] == 0x02)
			{
				Act485_Info.mode_tick = SysTick_1s;
			}else if(data[HEAD_LEN+1] == 0x03)
			{
				BUS485_Info.mode_tick = SysTick_1s;
			}
		
			/*将透传数据放到发送缓冲区*/
			temp_len = DataLen - 15 - 2 - 3;
			//Dbg_Println(DBG_BIT_NET_STATUS_bit,"NET temp_len:%d ",temp_len );
			Write_Uart_SendBuff(data[HEAD_LEN+1],data[HEAD_LEN+2],&data[HEAD_LEN+3],temp_len);
			break;
	}
	
	return 0x00;
}

/*************************
**函数名：Udp_Internal_SeriaNet_Uploading
**参  数：data_addr：需要上报处理 - 串口数据缓冲区 前2byte字节为数据长度 - 透传数据最长为480Byte
**作  用：BLV-C1透传数据上发
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_SeriaNet_Uploading(uint8_t port,uint32_t baud,uint32_t data_addr)
{
	uint8_t pc_ip[4];
	uint16_t pc_port = 0;
	uint32_t write_addr = data_addr;
	UINT32 data_len = SRAM_Read_Word(data_addr);
	
	if(data_len > Passthrough_DataLen_Max)	data_len = Passthrough_DataLen_Max;
	
	memset(pc_ip,0,sizeof(pc_ip));
	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	if((server_info.frame_no < 0xfffe) && (server_info.frame_no >= 0x8000))      
	{
		server_info.frame_no++;
	}
	else
	{
		server_info.frame_no = 0x8000;
	}
	/*读取PC IP地址*/
	SRAM_DMA_Read_Buff(pc_ip,4,SRAM_IAP_IP_ADDRESS);
	pc_port = SRAM_Read_Word(SRAM_IAP_PORT_ADDRESS);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_SeriaNet_Uploading IP:%02X.%02X.%02X.%02X Port:%d",pc_ip[0],pc_ip[1],pc_ip[2],pc_ip[3],pc_port);
	
	write_addr = data_addr+2;
	SRAM_DMA_Read_Buff(&Global_Large_Buff[HEAD_LEN + 2],data_len,write_addr);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_SeriaNet_Uploading Len:%d",data_len);
	
	data_len += 19;	//加上包头长度15Byte及包尾CRC2Byte
	/**/
	UDP_Add_Header(Global_Large_Buff,In_SeriaNetReported_Cmd,data_len,server_info.frame_no);            	//添加头部
	
	Global_Large_Buff[HEAD_LEN] = port;									//当前数据端口号
	Global_Large_Buff[HEAD_LEN + 1] = UDP_Baud_Conversion_Data(baud);	//当前数据波特率
	
	NetCRC16(&Global_Large_Buff[0],data_len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &Global_Large_Buff[0], &data_len, pc_ip, pc_port); 
	
	
	return 0x00;
	
}

/*************************
**函数名：Udp_Internal_SeriaNet_Uploading
**参  数：data_addr：需要上报处理 - 串口数据缓冲区 前2byte字节为数据长度 - 透传数据最长为480Byte
**作  用：BLV-C1透传数据上发
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_SeriaNet_Uploading2(uint8_t port,uint32_t baud,uint8_t* data, uint16_t DataLen)
{
	uint8_t pc_ip[4];
	uint16_t pc_port = 0;
	UINT32 data_len = DataLen + 19;
	
	if(data_len > Passthrough_DataLen_Max)	data_len = Passthrough_DataLen_Max;
	
	memset(pc_ip,0,sizeof(pc_ip));
	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	if((server_info.frame_no < 0xfffe) && (server_info.frame_no >= 0x8000))      
	{
		server_info.frame_no++;
	}
	else
	{
		server_info.frame_no = 0x8000;
	}
	/*读取PC IP地址*/
	SRAM_DMA_Read_Buff(pc_ip,4,SRAM_IAP_IP_ADDRESS);
	pc_port = SRAM_Read_Word(SRAM_IAP_PORT_ADDRESS);
	

	UDP_Add_Header(Global_Large_Buff,In_SeriaNetReported_Cmd,data_len,server_info.frame_no);            	//添加头部
	
	Global_Large_Buff[HEAD_LEN] = port;									//当前数据端口号
	Global_Large_Buff[HEAD_LEN + 1] = UDP_Baud_Conversion_Data(baud);	//当前数据波特率
	
	for(uint16_t i = 0;i<data_len - 19;i++)
	{
		Global_Large_Buff[HEAD_LEN + 2 + i] = data[i];
	}
	
	NetCRC16(&Global_Large_Buff[0],data_len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &Global_Large_Buff[0], &data_len, pc_ip, pc_port); 
	
	return 0x00;
}

/*************************
**函数名：Udp_Internal_SeriaNet_Uploading
**参  数：data_addr：需要上报处理 - 串口数据缓冲区 前2byte字节为数据长度 - 透传数据最长为480Byte
**作  用：BLV-C1透传数据上发
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_SeriaNet_Response_Timeout(void)
{
	uint8_t pc_ip[4];
	uint16_t pc_port = 0;

	UINT32 data_len = SeriaNet_Cmd_Send_Len;
	uint8_t back_data[SeriaNet_Cmd_Send_Len];
	
	memset(pc_ip,0,sizeof(pc_ip));
	memset(back_data,0,sizeof(back_data));
	
	if((server_info.frame_no < 0xfffe) && (server_info.frame_no >= 0x8000))      
	{
		server_info.frame_no++;
	}
	else
	{
		server_info.frame_no = 0x8000;
	}
	/*读取PC IP地址*/
	SRAM_DMA_Read_Buff(pc_ip,4,SRAM_IAP_IP_ADDRESS);
	pc_port = SRAM_Read_Word(SRAM_IAP_PORT_ADDRESS);
	

	UDP_Add_Header(back_data,In_SeriaNet_Cmd,data_len,server_info.frame_no);            	//添加头部
	back_data[HEAD_LEN] = 0x03;			//透传回复
	back_data[HEAD_LEN + 1] = 0x03;		//超时状态
	
	NetCRC16(&back_data[0],data_len);
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &data_len, pc_ip, pc_port); 
	
	
	return 0x00;
}

/*************************
**函数名：Udp_Internal_Set_MQTT_SecretKey_Process
**参  数：
**作  用：设置MQTT密钥处理函数
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_Set_MQTT_SecretKey_Process(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	/*CRC校验*/
	uint8_t rev = 0;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s\n",__func__);
	
	uint16_t frame_id = 0;
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	
	/*数据处理,判断数据是否合法*/
	if((data[UDP_PackData] == 'T') && (data[UDP_PackData + 1] == 'S') && (data[UDP_PackData + 2] == 'W') && (data[UDP_PackData + 3] == '1'))
	{
		if((data[UDP_PackData + 4] == MACAddr[0]) 		\
			&& (data[UDP_PackData + 5] == MACAddr[1]) 	\
			&& (data[UDP_PackData + 6] == MACAddr[2]) 	\
			&& (data[UDP_PackData + 7] == MACAddr[3]) 	\
			&& (data[UDP_PackData + 8] == MACAddr[4]) 	\
			&& (data[UDP_PackData + 9] == MACAddr[5]))
		{
			Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"设置MQTT密钥:",&data[UDP_PackData + 10],32);
			Flash_Write(&data[UDP_PackData + 10],32,FLASH_MCU_MQTT_START_ADDRESS+FLASH_MQTTINFO_DeviceSecret_OFFSET);	//将数据直接保存到Flash指定位置
		}
	}
	
	/*回复应答*/
	rev = Udp_Internal_Process_Ack(In_SetSecretKey_Cmd,frame_id,ip,port);
	return rev;
}

/*************************
**函数名：Udp_Internal_Read_MQTT_SecretKey_Process
**参  数：
**作  用：读取MQTT密钥处理函数
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_Read_MQTT_SecretKey_Process(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	/*CRC校验*/
	uint8_t rev = 0;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s\n",__func__);
	
	uint8_t temp = 0;
	UINT32 len = HEAD_LEN+44;

	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
//	uint16_t frame_id = 0;
//	frame_id = data[FRAME_NO_OFFSET];
//	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	
	UDP_Add_Header(Global_Large_Buff,In_ReadSecretKey_Cmd,len,0xffff);
	temp += HEAD_LEN;
	
	Global_Large_Buff[temp++] = 'T';
	Global_Large_Buff[temp++] = 'S';
	Global_Large_Buff[temp++] = 'W';
	Global_Large_Buff[temp++] = '1';
	UDP_Add_Mac(&Global_Large_Buff[temp]);
	temp+=6;
	/*读取MQTT 密钥参数 32Byte*/
	Flash_Read(&Global_Large_Buff[temp],32,FLASH_MCU_MQTT_START_ADDRESS+FLASH_MQTTINFO_DeviceSecret_OFFSET);
	NetCRC16(Global_Large_Buff,len);
	Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"读取MQTT密钥回复数据：",Global_Large_Buff,len);
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0],Global_Large_Buff,&len,ip,port);
	return rev;
}


/*************************
**函数名：Udp_Internal_Write_FlashInfo_Process
**参  数：
**作  用：读取MQTT密钥处理函数
**返回值：
	0x00：数据处理成功
	0xF0：接收数据的CRC校验失败
************************/
uint8_t Udp_Internal_Write_FlashInfo_Process(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{

	uint8_t rev = 0,result = 0x00;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	UINT32 len = HEAD_LEN+3;
	uint8_t back_data[20];
	memset(back_data,0,sizeof(back_data));
	
	uint32_t info_addr = 0;
	uint16_t frame_id = 0,result_len = 0;
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	
	if(data[UDP_PackData] == 0x01)		//表示写入MQTT参数
	{
		/*偏移地址加数据长度*/
		info_addr = data[UDP_PackData+4];
		info_addr <<= 8;
		info_addr |= data[UDP_PackData+3];
		info_addr <<= 8;
		info_addr |= data[UDP_PackData+2];
		info_addr <<= 8;
		info_addr |= data[UDP_PackData+1];
		
		result_len = data[UDP_PackData+6];
		result_len <<= 8;
		result_len |= data[UDP_PackData+5];
		
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"写入MQTT参数偏移地址：%08X,长度：%d",info_addr,result_len);
		
		if((info_addr < FLASH_MQTTINFO_END_OFFSET) && ((info_addr + result_len) < FLASH_MQTTINFO_END_OFFSET))
		{
			if(result_len <= (DataLen - 8 - UDP_PackData))
			{
				result = 0x01;
				Flash_Write(&data[UDP_PackData + 7],result_len,FLASH_MCU_MQTT_START_ADDRESS+info_addr);			//将数据直接保存到Flash指定位置
			}else {
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"写入长度不对");
			}
		}
	}

	
	UDP_Add_Header(back_data,In_BLVFlashInfoWrite_CMD,len,frame_id);
	back_data[UDP_PackData] = result;
	NetCRC16(back_data,len);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_Process_Ack --------");
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0],back_data,&len,ip,port);
	
	return rev;
}

uint8_t Udp_Internal_Read_FlashInfo_Process(uint8_t* data, uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t rev = 0;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	UINT32 len = HEAD_LEN + 2;

	memset(Global_Large_Buff,0,sizeof(Global_Large_Buff));
	
	uint32_t info_addr = 0;
	uint16_t frame_id = 0,result_len = 0;
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	
	if(data[UDP_PackData] == 0x01)		//表示写入MQTT参数
	{
		/*偏移地址加数据长度*/
		info_addr = data[UDP_PackData+4];
		info_addr <<= 8;
		info_addr |= data[UDP_PackData+3];
		info_addr <<= 8;
		info_addr |= data[UDP_PackData+2];
		info_addr <<= 8;
		info_addr |= data[UDP_PackData+1];
		
		result_len = data[UDP_PackData+6];
		result_len <<= 8;
		result_len |= data[UDP_PackData+5];
		
		Global_Large_Buff[UDP_PackData+0] = data[UDP_PackData+0];
		Global_Large_Buff[UDP_PackData+1] = data[UDP_PackData+1];
		Global_Large_Buff[UDP_PackData+2] = data[UDP_PackData+2];
		Global_Large_Buff[UDP_PackData+3] = data[UDP_PackData+3];
		Global_Large_Buff[UDP_PackData+4] = data[UDP_PackData+4];
		Global_Large_Buff[UDP_PackData+5] = data[UDP_PackData+5];
		Global_Large_Buff[UDP_PackData+6] = data[UDP_PackData+6];
		
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"读取MQTT参数偏移地址：%08X,长度：%d",info_addr,result_len);
		len += 7;
		if((info_addr < FLASH_MQTTINFO_END_OFFSET) && ((info_addr + result_len) < FLASH_MQTTINFO_END_OFFSET))
		{
			if(result_len >= 450)	result_len = 450;
			
			len += result_len;
			
			Flash_Read(&Global_Large_Buff[UDP_PackData + 7],result_len,FLASH_MCU_MQTT_START_ADDRESS+info_addr);			//将数据直接保存到Flash指定位置
		}else {
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"读取长度不对");
		}
	}

	UDP_Add_Header(Global_Large_Buff,In_BLVFlashInfoRead_CMD,len,frame_id);
	
	NetCRC16(Global_Large_Buff,len);
	Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"Udp_Internal_Read_FlashInfo_Process:",Global_Large_Buff,len);
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0],Global_Large_Buff,&len,ip,port);
	
	return rev;
}

/*************************
**函数名：Udp_Internal_Analysis
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：局域网服务的网络套接字接收数据处理       
**返回值：无        
*调用方式：局域网服务的网络套接字接收回调中调用
**
************************/
void Udp_Internal_Analysis(UINT8 *data, UINT32 len, uint8_t* ip, uint16_t port)
{
	uint8_t rev = 0;
	uint16_t cmd_length = 0;

	if((0xaa == data[FRAME_HEAD_OFFSET])&&(0x55 == data[FRAME_HEAD_OFFSET +1]))     //校验帧头
	{
		cmd_length = data[FRAME_LEN_OFFSET]+(data[FRAME_LEN_OFFSET +1]<<8);
		if((cmd_length <= NET_REV_LEN)&&(cmd_length>=UDP_FRAME_MIN_LEN))               //校验帧长度的最大值  
		{
			if((data[SYSTEM_ID_OFFSET] == 'T')&&(data[SYSTEM_ID_OFFSET +1] == '3')\
			&& (data[SYSTEM_ID_OFFSET +2] == 'S')&&(data[SYSTEM_ID_OFFSET +3] == 'A'))  //校验系统ID
			{
				switch(data[CMD_OFFSET])                                                  //校验帧长度
				{
					case IAP_Cmd:         //升级命令
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP 升级命令");
						if(len != IAP_Cmd_Rev_Len)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"数据长度不对");
							return ;
						}
						//在分配空间在函数内部有判断，此处不需要
//						if(IAPVarTypeStruct_Ptr == NULL)
//						{
//							IAPVarTypeStruct_Ptr = (IAPVarTypeStruct*)malloc(sizeof(IAPVarTypeStruct));   //分配空间
//						}
//						memset(IAPVarTypeStruct_Ptr, 0, sizeof(IAPVarTypeStruct));
						
						Udp_Internal_IAP(data, len, ip, port);
						break;
					case Subgroup_Cmd:       //发布子群命令
						if(IAPVarTypeStruct_Ptr == NULL)
						{
							IAPVarTypeStruct_Ptr = (IAPVarTypeStruct*)malloc(sizeof(IAPVarTypeStruct));   //分配空间
						}
						memset(IAPVarTypeStruct_Ptr, 0, sizeof(IAPVarTypeStruct));
						Udp_Internal_Subgroup(data, len, ip, port);
						break;
					case Search_Cmd:       //搜索命令
						Udp_Internal_Search(data, len, ip, port);
						break;
					case CLOUD_IAP_Cmd:
						if(IAPVarTypeStruct_Ptr == NULL)
						{
							IAPVarTypeStruct_Ptr = (IAPVarTypeStruct*)malloc(sizeof(IAPVarTypeStruct));   //分配空间
						}
						memset(IAPVarTypeStruct_Ptr, 0, sizeof(IAPVarTypeStruct));
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"云端TFTP 升级命令");
						UDP_CLOUD_IAP_Cmd(data, len, ip, port);
						break;
					case In_RoomState_Cmd:	//房间设备上报命令回复
	

						
						break;
					case In_DevCtr_Cmd:	//服务器下发设备控制
						Udp_Internal_Device_Control_Process(data, len, ip, port);
						break;
					case In_SingleAirCtrl_Cmd:     //温控器单控 季节下发
						Udp_Internal_SingleTempCtrl_dis(data, len, ip, port);
						break;
					case In_Sys_Key_Cmd:          //一键断电
						Udp_Internal_sys_key(data, len, ip, port);   //主机电源控制
						break;
					case In_ReadRegister_Cmd:		//读取映射寄存器内容 2021-07-13
						/*这读取寄存器内容，注意这不是MCU芯片的寄存器内容数据
							这是本机存储的一些特殊数据，并将数据规划好了地址空间用来存放
						*/
						rev = Udp_Internal_ReadRegister_Process(data, len, ip, port);
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net UDP CRC ERROR!");
						}
						
						break;
					case In_WriteRegister_Cmd:		//设置映射寄存器内容 2021-07-13
						/*这设置寄存器内容，注意这不是MCU芯片的寄存器内容数据
							寄存器内容：
						*/
						rev = Udp_Internal_WriteRegister_Process(data, len, ip, port);
						
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net UDP CRC ERROR!");
						}
					
						break;
					case In_BLVPCTest_Cmd:			//BLV-C1 PC测试设备连接状态 2021-07-13
						/*PC测试 - 测试设备端是否通讯正常
							轮询设备直接查看是否在线
							主动设备发送状态查询数据，查看数据是否正常
						*/
						rev = Udp_Internal_BLVPCTest_Process(data, len, ip, port);
					
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net UDP CRC ERROR!");
						}
						break;

					case In_BLVPCTestDevice_Cmd:	//BLV-C1 PC测试设备输入输出 2021-11-04
						
						Udp_Internal_BLVPCTestDevice_Process(data, len, ip, port);
					
						break;
					case In_SeriaNet_Cmd:
						Udp_Internal_SeriaNet_Process(data, len, ip, port);
						break;
					case In_SeriaNetReported_Cmd:
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net UDP In_SeriaNetReported_Cmd Relay!");
						break;
					case In_Set_RoomRent_Cmd:		//设置房态
						//出租信息下发 - 需要掉电保存
						
						Udp_Internal_RoomRent_Process(data, len, ip, port);
						break;
					case In_Read_MCUSystem_Cmd:		//读取MCU参数信息
						rev = Udp_Internal_Read_MCU_System_Process(data, len, ip, port);
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net UDP CRC ERROR!");
						}
						break;
					case In_BLVIAP_Cmd:			//BLV_Cx升级命令
						rev = Udp_Internal_BLVIAP(data, len, ip, port);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"BLV_Cx升级命令");
						LOG_LogicInfo_DebugRecord("BLV_Cx升级命令");
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net Udp_Internal_BLVIAP CRC ERROR!");
						}
						break;
					case In_BLVIAPCheck_Cmd:	//BLV_Cx升级校验命令
						rev = Udp_Internal_BLVIAPCheck_Process(data, len, ip, port);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"BLV_Cx升级校验命令");
						LOG_LogicInfo_DebugRecord("BLV_Cx升级校验命令");
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net Udp_Internal_BLVIAPCheck_Process CRC ERROR!");
						}
						break;
					case In_BLVIAPJump_Cmd:		//BLV_Cx跳转命令
						rev = Udp_Internal_BLVIAPJUMP_Process(data, len, ip, port);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"BLV_Cx跳转命令");
						LOG_LogicInfo_DebugRecord("BLV_Cx跳转命令");
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net Udp_Internal_BLVIAPJUMP_Process CRC ERROR!");
						}
						break;
					case In_BLVIAPLogic_Cmd:
						rev = Udp_Internal_BLVIAP_Logic(data, len, ip, port);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"BLV_Cx升级逻辑命令");
						LOG_LogicInfo_DebugRecord("BLV_Cx升级逻辑命令");
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Net Udp_Internal_BLVIAP CRC ERROR!");
						}
						break;
					case In_BLVIAPPlan_Cmd:
						//无接收处理
						break;
					
					case In_QueryTime_Cmd:   	//时间同步
						Udp_Internal_GetTime_Process(data, len, ip, port);
						break;
					case In_Get_RoomRent_Cmd:	//获取房态信息
						Udp_Internal_GetRoomRent_Process(data, len, ip, port);
						break;
					case In_Reboot_Reason_Cmd:	//向服务器上报 重启原因
						Udp_Internal_Reboot_Reason_Report_Process(data, len, ip, port);
						break;
					case In_PeriodicReport_Cmd:	//定期上报
						Udp_Internal_Periodic_Report_Process(data, len, ip, port);
						break;
					case In_Power_Change_Cmd:	//取电状态变化上报
						Udp_Internal_Power_Change_Report_Process(data, len, ip, port);
						break;
					case In_DevState_Cmd:		//设备状态上报
						Udp_Internal_RoomState_Process(data, len, ip, port);
						break;
					case Heart_Cmd:				//心跳包
						server_info.udp_online_tick = SysTick_1ms;	//心跳包这里只更新UDP在线时间戳
						break;
					
					case In_BLVDayNightTimeSet_Cmd:   //白天时间范围设置    2024-08-02
						Udp_Internal_DayTimeSet_Process(data, len, ip, port);
						break;
#if MQTT_EN				
					//2025-09-27	现在没有使用MQTT相关内容，因此命令取消 
					case In_SetSecretKey_Cmd:	//云端服务器 - 设置MQTT密钥 2021-12-01
						Udp_Internal_Set_MQTT_SecretKey_Process(data, len, ip, port);

						ALIYUN_Flash_Parameter_Init(&mqtt_info);    //下发密钥后初始化阿里云  2022-09-03
						mqtt_info.mqtt_sta = MQTT_DNS;              //设置密钥后，重新初始化MQTT_DNS    2023-03-17

						break;
					case In_ReadSecretKey_Cmd:	//云端服务器 - 读取MQTT密钥	2021-12-01
						Udp_Internal_Read_MQTT_SecretKey_Process(data, len, ip, port);
						break;
					case In_BLVFlashInfoWrite_CMD:	//写Flash参数信息	2021-12-02
						Udp_Internal_Write_FlashInfo_Process(data, len, ip, port);
						break;
					case In_BLVFlashInfoRead_CMD:	//读取Flash参数信息	2021-12-02
						Udp_Internal_Read_FlashInfo_Process(data, len, ip, port);
						break;
#endif				

#if TFTP_GET_IP
					case In_BLVQueryTFTPIP_CMD:     //获取TFTP日志服务器ＩＰ
						rev = Udp_Internal_QueryTFTPIP_Process(data, len, ip, port);
						server_info.tftpip_gflag = 0x01;
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_QueryTFTPIP_Process CRC ERROR!");
						}
						break;
#endif
					case In_BLVTFTPDomainName_Cmd:  //设置TFTP服务器域名
						Udp_Internal_TFTPDNSet_Process(data, len, ip, port);
						if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_TFTPDNSet_Process ERROR!");
						}
						break;
					case In_BLVTFTPDataRead_Cmd:    //TFTP服务器信息读取
						Udp_Internal_TFTPData_Read_Process(data, len, ip, port);
				        if(rev == 0xF0)
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"Udp_Internal_TFTPData_Read_Process ERROR!");
						}
						break;
					default: break;
				}
				
				LOG_NET_COMM_Recv_Record(0x01,ip,port,data,len);
			}
		}
	}
}

/**
  * @brief Returns the TFTP opcode 
  * @param buf: pointer on the TFTP packet 
  * @retval none
  */
tftp_opcode IAP_tftp_decode_op(char *buf)
{
	return (tftp_opcode)(buf[1]);
}

/*************************
**函数名：TFTP_CMD_Analysis
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：TFTP服务的网络套接字接收命令解析处理      
**返回值：无        
*调用方式：TFTP服务的网络套接字接收回调中调用
**
************************/
void TFTP_CMD_Analysis(UINT8 *data, UINT32 len, uint8_t* ip, uint16_t port)
{
	if(TFTP_WRQ == IAP_tftp_decode_op((char *)data))   //如果是写
	{
		IAPVarTypeStruct_Ptr->TftpStart = TFTPWRITESTART; 
		if(tftp_args == NULL)
		{
			tftp_args = (tftp_connection_args*)malloc(sizeof(tftp_connection_args));    //分配空间
		}
		memset(tftp_args, 0, sizeof(tftp_connection_args));
		memcpy(server_info.goal_ip, ip, 4);
		server_info.goal_port = port;
	}
	else if(TFTP_OPTION == IAP_tftp_decode_op((char *)data))   //接收到写日志请求回复
	{
		//Read_Journal_CMD_ACK(SOCK_TFTP_CMD, ip_cmd, port_cmd);      
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"接收到写日志请求回复---");
		
		IAPVarTypeStruct_Ptr->TftpStart = TFTPWRITEJOURNAL;
		if(tftp_args == NULL)
		{
			tftp_args = (tftp_connection_args*)malloc(sizeof(tftp_connection_args));    //分配空间
		}
		memset(tftp_args, 0, sizeof(tftp_connection_args));
		memcpy(server_info.goal_ip, ip, 4);
		server_info.goal_port = port;
	}

}

/**
*@brief	 	16位字符高8位低8位转换
*@param		i:要转化的数据
*@return	转换后的数据
*/
uint16 swaps(uint16 i)
{
  uint16 ret=0;
  ret = (i & 0xFF) << 8;
  ret |= ((i >> 8)& 0xFF);
  return ret;	
}

/**
*@brief		将一个 主机模式的unsigned short型数据转换到大端模式的TCP/IP 网络字节格式的数据.
*@param		要转换的数据
*@return 	大端模式的数据
*/ 
uint16 Htons( 
	uint16 hostshort	/**< A 16-bit number in host byte order.  */
	)
{
#if ( SYSTEM_ENDIAN == _ENDIAN_LITTLE_ )
	return swaps(hostshort);
#else
	return hostshort;
#endif		
}

/**
*@brief		将一个大端模式的TCP/IP 网络字节格式的数据转换到主机模式的unsigned short型数据
*@param		要转换的数据
*@return 	unsigned short模式的数据
*/ 
unsigned long Ntohs(
	unsigned short netshort	/**< netshort - network odering 16bit value */
	)
{
#if ( SYSTEM_ENDIAN == _ENDIAN_LITTLE_ )	
	return Htons(netshort);
#else
	return netshort;
#endif		
}

/**
  * @brief  Extracts the block number
  * @param  buf: pointer on the TFTP packet 
  * @retval block number
  */
static uint16_t IAP_tftp_extract_block(char *buf)
{
	uint16_t *b = (uint16_t*)buf;
	return Ntohs(b[1]);
}

static void IAP_tftp_set_opcode(char *buffer, tftp_opcode opcode)
{
	buffer[0] = 0;
	buffer[1] = (uint8_t)opcode;
}

/**
  * @brief Sets the TFTP block number 
  * @param packet: pointer on the TFTP packet 
  * @param  block: block number
  * @retval none
  */
static void IAP_tftp_set_block(char* packet, uint16_t block)
{
	uint16_t *p = (uint16_t *)packet;
	p[1] = Htons(block);
}


/*******************************************************************************
* Function Name  : IAP_AckState
* Description    : 局域网升级状态回复
* Input          : 
	state 	: 升级状态
	to_ip 	: 目的IP
	to_port	：目的端口
* Return         : None
*******************************************************************************/
void IAP_AckState(uint8_t state, uint8_t* ip, uint16_t port)
{
	uint8_t back_data[IAP_Cmd_Send_Len]={0};
	UINT32 sendlen = IAP_Cmd_Send_Len;
	
	//处理要返回的数据帧
	UDP_Add_Header(back_data,IAP_Cmd,IAP_Cmd_Send_Len,0xfffe);             		//添加头部
	back_data[IAP_Cmd_Send_State] = state;                                    	//升级就绪
	UDP_ADD_SoftwareVer(&back_data[IAP_Cmd_Send_SoftwareVer]);         		 	//添加固件版本
	NetCRC16(&back_data[0],IAP_Cmd_Send_Len);
	
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);
}


/*******************************************************************************
* Function Name  : CLOUD_IAP_AckState
* Description    : 云端升级状态回复
* Input          : 
	s 			: 套接字ID号
	to_ip 		: 目的IP
	to_port		：目的端口
	file_type   ：文件类型
* Return         : None
*******************************************************************************/
void CLOUD_IAP_AckState(uint8_t Cmd, uint8_t state, uint8_t* ip, uint16_t port,uint8_t file_type)
{
	uint8_t back_data[CLOUD_IAP_Cmd_Send_Len]={0};
	
	//处理要返回的数据帧
	UDP_Add_Header(back_data,Cmd,CLOUD_IAP_Cmd_Send_Len,0xfffe);              		//添加头部
	back_data[CLOUD_IAP_Cmd_Send_State] = state;                                  	//升级就绪
	UDP_ADD_SoftwareVer(&back_data[CLOUD_IAP_Cmd_Send_SoftwareVer]);         		//添加固件版本
	back_data[CLOUD_IAP_Cmd_Send_Filetype] = file_type;
	NetCRC16(&back_data[0],CLOUD_IAP_Cmd_Send_Len);
	UINT32 sendlen = CLOUD_IAP_Cmd_Send_Len;
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);
}


/*******************************************************************************
* Function Name  : CFG_AckState
* Description    : 局域网升级错误状态回复
* Input          : 
	s 		: 套接字ID号
	to_ip 	: 目的IP
	to_port	：目的端口
* Return         : None
*******************************************************************************/
void CFG_AckState(uint8_t state,uint8_t* ip,uint16_t port)
{
	uint8_t back_data[CONFIG_Cmd_Send_Len]={0};
	//处理要返回的数据帧
	UDP_Add_Header(back_data,Subgroup_Cmd,CONFIG_Cmd_Send_Len,0xffff);         		//添加头部
	back_data[CONFIG_Cmd_Send_State] = state;
	NetCRC16(&back_data[0],CONFIG_Cmd_Send_Len);
	UINT32 sendlen = CONFIG_Cmd_Send_Len;
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);
}

/*******************************************************************************
* Function Name  : LOGIC_Config_AckState
* Description    : BLV_Cx配置下发升级错误状态回复 - 统一回复命令：0x0A
* Input          : 
	s 		: 套接字ID号
	to_ip 	: 目的IP
	to_port	：目的端口
* Return         : None
*******************************************************************************/
void LOGIC_Config_AckState(uint8_t state,uint8_t* ip,uint16_t port)
{
	uint8_t back_data[CONFIG_Cmd_Send_Len]={0};
	//处理要返回的数据帧
	UDP_Add_Header(back_data,IAP_Cmd,CONFIG_Cmd_Send_Len,0xffff);         		//添加头部
	back_data[CONFIG_Cmd_Send_State] = state;
	NetCRC16(&back_data[0],CONFIG_Cmd_Send_Len);
	UINT32 sendlen = CONFIG_Cmd_Send_Len;
	CH57xNET_SocketUdpSendTo(net_info.SocketId[0], &back_data[0], &sendlen, ip, port);
}


/*******************************************************************************
* Function Name  : IAP_tftp_process_read
* Description    : TFTP获取云端文件 - 云端下发升级命令之后，需要MCU主动向云端获取文件
* Input          : 
	s 		: 套接字ID号
	to_ip 	: 云端的IP
	to_port	：云端的接收端口 - 在云端下发升级命令中会携带接收的端口号
* Return         : None
*******************************************************************************/
uint8_t IAP_tftp_process_read(uint8_t s, uint8_t* to_ip, int to_port)  
{
	uint8_t rrq_data[150];          //64文件获取报文报文
	UINT32 rrq_length = 0;

	IAPVarTypeStruct_Ptr->TotalCount =0; 

	IAPVarTypeStruct_Ptr->IapErrFlag = 0;


	if(IAPVarTypeStruct_Ptr->IapFileType == DATATYPE_IAP)
	{
	
		IAPVarTypeStruct_Ptr->FlashWriteAddress = SRAM_IAP_APP_FILE_ADDRESS;	//设置写地址 - 数据先保存在SRAM中
	}
	else if(IAPVarTypeStruct_Ptr->IapFileType == DATATYPE_CONFIG)		//暂时没有了
	{
		IAPVarTypeStruct_Ptr->FlashWriteAddress = SRAM_IAP_LOGIC_DataStart_ADDRESS;	//设置写地址 - 数据先保存在SRAM中
	}
	else
	{
		return 1;
	}

	rrq_data[0] = 0x00;
	rrq_data[1] = 0x01;
	memcpy(&rrq_data[2], IAPVarTypeStruct_Ptr->FtpFileName, IAPVarTypeStruct_Ptr->FtpFileNameLen);   //从文件名的位置去拷取文件 总长度

	rrq_length += IAPVarTypeStruct_Ptr->FtpFileNameLen+2; 
	rrq_data[rrq_length++] = 0;
	rrq_data[rrq_length++] = 'o';  //octet 因特网标准使用八位组
	rrq_data[rrq_length++] = 'c';
	rrq_data[rrq_length++] = 't';
	rrq_data[rrq_length++] = 'e';
	rrq_data[rrq_length++] = 't';
	rrq_data[rrq_length++] = 0;
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"FtpFileNameLen:%d , name:%s",IAPVarTypeStruct_Ptr->FtpFileNameLen,IAPVarTypeStruct_Ptr->FtpFileName);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SocketId:%d , port:%d , len:%ld , IP:%d.%d.%d.%d",s,to_port,rrq_length,to_ip[0],to_ip[1],to_ip[2],to_ip[3]);
//	Dbg_Println(DBG_BIT_NET_STATUS_bit,"Data:");
//	for(uint16_t j = 0;j<rrq_length;j++)
//	{
//		Dbg_Println(DBG_BIT_NET_STATUS_bit,"%02X ",rrq_data[j]);
//	}
//	Dbg_Println(DBG_BIT_NET_STATUS_bit,"\n");
	
	CH57xNET_SocketUdpSendTo(s,&rrq_data[0],&rrq_length,to_ip,to_port);     //RCU主动发送文件获取命令

	return 0;
}

/*测试TFTP 通讯数据可以上云端指定的TFTP端口 65500~65509*/
uint8_t TFTP_LOG_Write_Connect(uint8_t* to_ip,int to_port)
{
	uint8_t temp_buff[4] = {0xFF,0xFF,0xFF,0xFF};
	UINT32 data_len = 0x04;

	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s - %d",__func__,to_port);
	
	CH57xNET_SocketUdpSendTo(net_info.SocketId[1],temp_buff,&data_len,to_ip,to_port);
	
	return 0;
}

/*测试TFTP 发送LOG写请求*/
uint8_t TFTP_LOG_Write_Requests(uint8_t* to_ip, int to_port)
{
	uint8_t res = 0;
	uint32_t addr_temp = 0,temp1 = 0;
	
	if(IAPVarTypeStruct_Ptr == NULL)	return 1;
	if(tftp_args == NULL)
	{
		tftp_args = (tftp_connection_args*)malloc(sizeof(tftp_connection_args));    //分配空间
	}
	memset(tftp_args, 0, sizeof(tftp_connection_args));
	
	/*获取日志文件大小 - 改进日志存储方式与读取地址*/
	addr_temp = SRAM_Get_TFTP_READ_Log_Address();			//获取SRAM中日志保存结束地址
	
	if(IAPVarTypeStruct_Ptr->FlashWriteAddress > addr_temp)
	{
		IAPVarTypeStruct_Ptr->TotalCount = IAPVarTypeStruct_Ptr->FlashWriteAddress - addr_temp;							//获取SRAM中日志保存大小 - 也就是需要写入的大小
	}else if(IAPVarTypeStruct_Ptr->FlashWriteAddress < addr_temp)	
	{
		IAPVarTypeStruct_Ptr->TotalCount = SRAM_LOG_End_Address - addr_temp;
		IAPVarTypeStruct_Ptr->TotalCount += IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_LOG_DATA_Address;
	}else if(IAPVarTypeStruct_Ptr->FlashWriteAddress == addr_temp)
	{
		return 0xF0;
	}
	
	
	/*获取日志块号*/
	IAPVarTypeStruct_Ptr->BlockSize = IAPVarTypeStruct_Ptr->TotalCount/512;	
	if( (IAPVarTypeStruct_Ptr->TotalCount%512) != 0x00)	IAPVarTypeStruct_Ptr->BlockSize+=1;
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"SRAM : %08X , TFTP GET LOG SIZE:%d , Block:%d",Get_Log_Current_Address(),IAPVarTypeStruct_Ptr->TotalCount,IAPVarTypeStruct_Ptr->BlockSize);
	
	/*打包TFTP发送写请求数据*/
	/*TFTP write request*/
	tftp_args->data[0] = 0x00;
	tftp_args->data[1] = 0x02;
	tftp_args->data_len += 2;
	/*TFTP File name*/
	temp1 = SRAM_Read_DW(SRAM_Register_Start_ADDRESS + Register_RoomNumber_OFFSET);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"File:%02X%02X%02X%02X_%04d_%04d_%02X%02X%02X%02X%02X%02X.dat",\
		MACAddr[2],MACAddr[3],MACAddr[4],MACAddr[5],\
		ProjectCode,\
		temp1,\
		RTC_Raw_Data.year,RTC_Raw_Data.month,RTC_Raw_Data.day,RTC_Raw_Data.hour,RTC_Raw_Data.minute,RTC_Raw_Data.second);
	
	//tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],40,"%04d_%04d_20%02X%02X%02X%02X%02X%02X.dat",ProjectCode,temp1,RTC_Raw_Data.year,RTC_Raw_Data.month,RTC_Raw_Data.day,RTC_Raw_Data.hour,RTC_Raw_Data.minute,RTC_Raw_Data.second);
	tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],40,"%02X%02X%02X%02X_%04d_%04d_%02X%02X%02X%02X%02X%02X.dat",\
		MACAddr[2],MACAddr[3],MACAddr[4],MACAddr[5],\
		ProjectCode,\
		temp1,\
		RTC_Raw_Data.year,RTC_Raw_Data.month,RTC_Raw_Data.day,RTC_Raw_Data.hour,RTC_Raw_Data.minute,RTC_Raw_Data.second);
	tftp_args->data[tftp_args->data_len++] = 0x00;
	tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],10,"octet");
	tftp_args->data[tftp_args->data_len++] = 0x00;
	tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],10,"blksize");
	tftp_args->data[tftp_args->data_len++] = 0x00;
	//tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],10,"%d",IAPVarTypeStruct_Ptr->BlockSize);
	tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],10,"512");
	tftp_args->data[tftp_args->data_len++] = 0x00;
	tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],10,"tsize");
	tftp_args->data[tftp_args->data_len++] = 0x00;
	tftp_args->data_len += snprintf((char *)&tftp_args->data[tftp_args->data_len],10,"%d",IAPVarTypeStruct_Ptr->TotalCount);
	tftp_args->data[tftp_args->data_len++] = 0x00;
	
	res = CH57xNET_SocketUdpSendTo(net_info.SocketId[1],tftp_args->data,&tftp_args->data_len,to_ip,to_port);     //RCU主动发送文件获取命令
	return res;
}

uint8_t IAP_tftp_write_LOG_Data(uint8_t* to_ip, int to_port)
{
	uint8_t res = 0;
	uint16_t datalen,datalen_1 = 0;
	uint32_t surplus_byte = IAPVarTypeStruct_Ptr->TotalCount - IAPVarTypeStruct_Ptr->WriteCount;
	uint32_t read_addr = SRAM_Get_TFTP_READ_Log_Address();		//TFTP日志当前读取地址
	
	if(tftp_args == NULL) return 0;
	memset(tftp_args->data, 0, sizeof(TFTP_DATA_LEN_MAX));
	
	if((surplus_byte == 0x00) || (tftp_args->block >= IAPVarTypeStruct_Ptr->BlockSize ))	return 1;
	
	/*读取地址*/
	if( (read_addr + IAPVarTypeStruct_Ptr->WriteCount) > SRAM_LOG_End_Address)	
	{
		read_addr = read_addr + IAPVarTypeStruct_Ptr->WriteCount - SRAM_LOG_End_Address + SRAM_LOG_DATA_Address;
	}else {
		read_addr += IAPVarTypeStruct_Ptr->WriteCount;
	}
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP read_addr : %08X , surplus_byte :%08X",read_addr,surplus_byte);
	tftp_args->block++;
	
	/*TFTP write data*/
	tftp_args->data[0] = 0x00;
	tftp_args->data[1] = 0x03;
	/*TFTP Write Data 当前块号*/
	tftp_args->data[2] = (tftp_args->block >> 8) & 0xFF;
	tftp_args->data[3] = tftp_args->block & 0xFF;

	/*TFTP File data - 从SRAM中读取LOG数据*/
	if(surplus_byte > 512) 	tftp_args->data_len = 512;
	else tftp_args->data_len = surplus_byte;
	
	if((tftp_args->data_len + read_addr) > SRAM_LOG_End_Address)	
	{
		datalen = SRAM_LOG_End_Address - read_addr;
		SRAM_Read_Buff(&tftp_args->data[4],datalen,read_addr);
		
		datalen_1 = tftp_args->data_len - datalen;
		read_addr = SRAM_LOG_DATA_Address;
		SRAM_Read_Buff(&tftp_args->data[4+datalen],datalen_1,read_addr);
	}else {
		SRAM_Read_Buff(&tftp_args->data[4],tftp_args->data_len,read_addr);
	}
	
	IAPVarTypeStruct_Ptr->WriteCount += tftp_args->data_len;
	
	tftp_args->data_len += 4;
	
	res = CH57xNET_SocketUdpSendTo(net_info.SocketId[1],tftp_args->data,&tftp_args->data_len,to_ip,to_port);     //RCU主动发送文件获取命令

	return res;
}

uint8_t IAP_tftp_Retry_write_LOG_Data(uint8_t* to_ip, int to_port)
{
	uint8_t res = 0;
	/*数据已在tftp_args->data，不需要重新填写数据*/
	
	res = CH57xNET_SocketUdpSendTo(net_info.SocketId[1],tftp_args->data,&tftp_args->data_len,to_ip,to_port);     //RCU主动发送文件获取命令

	return res;
}


void TFTP_LOG_CallBack(struct _SCOK_INF * SocketInf,UINT32 ipaddr,UINT16 port,UINT8 *buff,UINT32 len)
{
	UINT8 ip[4];
	
	ip[0] = ipaddr;
	ip[1] = ipaddr>>8;
	ip[2] = ipaddr>>16;
	ip[3] = ipaddr>>24;
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"ip:%d.%d.%d.%d, port:%d",ip[0], ip[1], ip[2], ip[3], port);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"Socket%d len:%ld ",net_info.SocketId[1] ,len);
	Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,",Recive: ",buff,len);


	/*TFTP数据内容解析*/
	if(TFTP_WRQ == IAP_tftp_decode_op((char *)buff))   //如果是写
	{
		IAPVarTypeStruct_Ptr->TftpStart = TFTPWRITESTART; 
		if(tftp_args == NULL)
		{
			tftp_args = (tftp_connection_args*)malloc(sizeof(tftp_connection_args));    //分配空间
		}
		memset(tftp_args, 0, sizeof(tftp_connection_args));
		memcpy(server_info.goal_ip, ip, 4);
		server_info.goal_port = port;
	}
	else if(TFTP_OPTION == IAP_tftp_decode_op((char *)buff))   //接收到写日志请求回复
	{
		//Read_Journal_CMD_ACK(SOCK_TFTP_CMD, ip_cmd, port_cmd);      
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"接收到写日志请求回复---");
		
		IAPVarTypeStruct_Ptr->TftpStart = TFTPWRITEJOURNAL;
		if(tftp_args == NULL)
		{
			tftp_args = (tftp_connection_args*)malloc(sizeof(tftp_connection_args));    //分配空间
		}
		memset(tftp_args, 0, sizeof(tftp_connection_args));
		memcpy(server_info.goal_ip, ip, 4);
		server_info.goal_port = port;
		
		TFTP_LOG_sta = STA_SEND_LOG;
	}
	else if(TFTP_ERROR == IAP_tftp_decode_op((char *)buff))
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP_ERROR ---");
		TFTP_LOG_sta = STA_END;
	}
	else if(TFTP_ACK == IAP_tftp_decode_op((char *)buff))
	{
		uint16_t block_num = 0;
		
		block_num = buff[2];
		block_num <<= 8;
		block_num |= buff[3];
		
		if(block_num == tftp_args->block){
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP_ACK Block:%d - %d",tftp_args->block,IAPVarTypeStruct_Ptr->BlockSize);
			TFTP_LOG_sta = STA_SEND_LOG;
			
			//判断当前发送块号与总包号是否相同，同时写入长度已达总长度
			if((tftp_args->block == IAPVarTypeStruct_Ptr->BlockSize) && (IAPVarTypeStruct_Ptr->TotalCount == IAPVarTypeStruct_Ptr->WriteCount))
			{
				SRAM_Set_TFTP_READ_LOG_Address(IAPVarTypeStruct_Ptr->FlashWriteAddress);
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"LOG Data Send Complete , addr:%08X!!!!",IAPVarTypeStruct_Ptr->FlashWriteAddress);
				TFTP_LOG_sta = STA_END;
			}
		}else{
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP_ACK Block Error:%d - %d - %d",tftp_args->block,IAPVarTypeStruct_Ptr->BlockSize,block_num);
		}
	}
}


/*******************************************************************************
* Function Name  : IAP_tftp_send_ack_packet
* Description    : 发送TFTP 应答数据
* Input          : None
* Return         : 返回发送状态
*******************************************************************************/
uint8_t IAP_tftp_send_ack_packet(uint8_t s, uint8_t *to_ip, int to_port, int block)
{
	uint8_t err = 0;
	UINT32 sendlen = TFTP_ACK_PKT_LEN;
	char packet[TFTP_ACK_PKT_LEN];

	/* define the first two bytes of the packet */
	if(1 == IAPVarTypeStruct_Ptr->IapErrFlag)	IAP_tftp_set_opcode(packet,TFTP_ERROR);
		else	IAP_tftp_set_opcode(packet, TFTP_ACK);

	IAP_tftp_set_block(packet, block);

	Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP ACK packet -- SocketId:%d , port:%d ,block:%ld len:%ld , IP:%d.%d.%d.%d",s,to_port,block,sendlen,to_ip[0],to_ip[1],to_ip[2],to_ip[3]);
	err = CH57xNET_SocketUdpSendTo(s, (uint8_t *)&packet[0], &sendlen, to_ip, to_port);

	return err;
}


uint8_t Cloud_IAP_Plan_SendPack( tftp_connection_args* tftp_con_args,IAPVarTypeStruct* IAP_Info,uint8_t iap_state)
{
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s -------",__func__);
	
	if( (tftp_con_args == NULL) || (IAP_Info == NULL) )	return 0x00;
	
	UINT32 len = UDP_PackData;
	uint8_t data_buffer[514];      //存512字节升级数据，后面用来读取2k数据校验CRC
	uint8_t rev = 0;
	
	if((server_info.frame_no < 0xfffe) && (server_info.frame_no >= 0x8000))      
	{
		server_info.frame_no++;
	}
	else
	{
		server_info.frame_no = 0x8000;
	}
	
	data_buffer[len++] = iap_state;								//升级状态
	data_buffer[len++] = IAP_Info->IapFileType;					//升级的文件类型
	
	data_buffer[len++] = (IAP_Info->BlockSize & 0xFF);			//升级文件总块数
	data_buffer[len++] = ((IAP_Info->BlockSize >> 8) & 0xFF);	//升级文件总块数
	
	data_buffer[len++] = (tftp_con_args->block & 0xFF);			//升级文件的当前块数
	data_buffer[len++] = ((tftp_con_args->block >> 8) & 0xFF);	//升级文件的当前块数
	
	data_buffer[len++] = IAP_Info->FtpFileNameLen;
	
	memcpy(&data_buffer[len],IAP_Info->FtpFileName,IAP_Info->FtpFileNameLen);
	len += IAP_Info->FtpFileNameLen;
	
	UDP_Add_Header(data_buffer,In_BLVIAPPlan_Cmd,len,server_info.frame_no);
	
	NetCRC16(data_buffer,len);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"IAP Block Sum:%d - Num:%d ",IAP_Info->BlockSize,tftp_con_args->block);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"IAP File_len:%d %s",IAP_Info->FtpFileNameLen,IAP_Info->FtpFileName);
	
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0],data_buffer,&len,server_info.dis_ip, server_info.dis_port);
	
	return rev;
}


/**
  * @Name   IAP升级，接收每一包数据临时保存到SRAM中，并对每一包下发的数据进行回复，接收完成并校验通过后保存flash中
  * @Param  
  *    _args   已经定义的文件传输时，用到的全局变量
  *    s       文件操作套接字
  *    pkt_buf 传过来的数据包
  *    pkt_buf_len 传过来的数据包长度
  *    ip_addr     目标IP地址
  *    port        目标端口号
  * @retval 无
  */
void IAP_wrq_recv_callback(void *_args, uint8_t s, uint8_t *pkt_buf,uint16_t pkt_buf_len,uint8_t *ip_addr, uint16_t Port)
{
	tftp_connection_args *args = (tftp_connection_args *)_args;
	uint8_t data_buffer[514];      //存512字节升级数据，后面用来读取2k数据校验CRC
	uint16 count=0;                    //每次升级文件内容按照u32来计数，不足一个u32按照一个u32计
	UINT32 i=0;
	uint32_t temp_var = 0;
	uint16_t CRC_Val = 0;
	uint16_t CRC_Num = 0;
	UINT8 ip[4];
	uint16 port;

	for(i=0;i<512;i++)
	{
		data_buffer[i] = 0xFF;
	}
	
	SRAM_DMA_Read_Buff(ip, 4, SRAM_IAP_IP_ADDRESS);
	port = SRAM_Read_Byte(SRAM_IAP_PORT_ADDRESS) | SRAM_Read_Byte(SRAM_IAP_PORT_ADDRESS+1)<<8;
	
	if((IAPVarTypeStruct_Ptr == NULL) && (args == NULL) )	return ;	
	
	IAPVarTypeStruct_Ptr->IapPercent++;
	IAPVarTypeStruct_Ptr->processing_tick = SysTick_1ms;

	if ( (pkt_buf_len > TFTP_DATA_PKT_HDR_LEN) && (IAP_tftp_extract_block((char *)pkt_buf) == (args->block + 1)) )		//数据包超过头长度
	{
		/* copy packet payload to data_buffer */
		//memcpy(args->data, &pkt_buf[TFTP_DATA_PKT_HDR_LEN], pkt_buf_len-TFTP_DATA_PKT_HDR_LEN);  //将除去报文头的数据拷贝过来
		for(uint32_t k=0;k<pkt_buf_len-TFTP_DATA_PKT_HDR_LEN;k++)
		{
			data_buffer[k] = pkt_buf[TFTP_DATA_PKT_HDR_LEN+k];
		}
		IAPVarTypeStruct_Ptr->TotalCount += pkt_buf_len - TFTP_DATA_PKT_HDR_LEN;        //字节总数  只算内容
		
		count = (pkt_buf_len - TFTP_DATA_PKT_HDR_LEN+3)/4;     //当前字节数据包的u32计数,如果当前字节数据包不是4的倍数，就加一
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"IapFileType:%d",IAPVarTypeStruct_Ptr->IapFileType);
		switch(IAPVarTypeStruct_Ptr->IapFileType)
		{
			case DATATYPE_IAP:                            //升级文件类型为bin文件
				if(0 == args->block)                              //如果是第0块 
				{
					temp_var = data_buffer[0] + (data_buffer[1]<<8) + (data_buffer[2]<<16) + (data_buffer[3]<<24);
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"temp_var : %08X ,block :%d",temp_var,args->block);
					if (((temp_var & 0x2FFE0000) != 0x20000000) /*||        //第0个u32   内存分配的地址不是有效的
						(data_buffer[1]<IAP_RUN_START_PAGE_ADDRESS)||             //第1个u32在指定的范围   入口函数不是处于应用函数的范围
						(data_buffer[1]>IAP_RUN_END_PAGE_ADDRESS)*/)
					{
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"内存分配的地址不是有效的");
	
						Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"pkt_buf:",pkt_buf,pkt_buf_len);
						Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"data:",data_buffer,pkt_buf_len-TFTP_DATA_PKT_HDR_LEN);
						
						
						switch(IAPVarTypeStruct_Ptr->IapType)
						{
							case IAPTFTPWRITE:		//升级文件错误	
								IAP_AckState(IAP_Error_File,(uint8_t *)ip,(uint16_t)port);  
								break;  
							case IAPTFTPREAD:
								CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Error_File, (uint8_t *)ip, (uint16_t)port, DATATYPE_IAP); 
								break;
						}
						IAPVarTypeStruct_Ptr->IapErrFlag = 1;                                                                //升级错误标志置一
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级失败，地址错误 data_buffer[0] & 0x2FFE0000 = %X; data_buffer[1]=%X\n", (data_buffer[0] & 0x2FFE0000), data_buffer[1]);
					}
				}
				else if(args->block > RUN_MAX_BLOCK)                            //如果超过APP最大内存范围（218K）数据
				{
					switch(IAPVarTypeStruct_Ptr->IapType)
					{
						case IAPTFTPWRITE:		//回复升级块错误
							IAP_AckState(IAP_Error_Block, (uint8_t *)ip, (uint16_t)port);                   
							break;   
						case IAPTFTPREAD:
							CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Error_Block, (uint8_t *)ip, (uint16_t)port, DATATYPE_IAP); 
							break; 
					}
					IAPVarTypeStruct_Ptr->IapErrFlag = 1;                                                                //升级错误标志置一
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级失败，超出最大块数\n");
				}
				
				
				
				break;
			case DATATYPE_CONFIG: 				//升级文件类型为cfg文件
				if(0 == args->block)
				{
//					temp_var = args->data[0] + (args->data[1]<<8) + (args->data[2]<<16) + (args->data[3]<<24);
//					Dbg_Println(DBG_BIT_NET_STATUS_bit,"temp_var : %0x08X\n",temp_var);
//					if(HEAD_SOFT_COM!=(temp_var&HEAD_SOFT_COM))      //判断升级配置文件头   配置软件版本不匹配	//文件类型错误
//					{
//						switch(IAPVarTypeStruct_Ptr->IapType)
//						{
//							case IAPTFTPWRITE:	//回复升级文件错误
//								LOGIC_Config_AckState(IAP_Error_File, (uint8_t *)ip, (uint16_t)port); 
//								break;     
//							case IAPTFTPREAD:
//								CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Error_File, (uint8_t *)ip, (uint16_t)port, DATATYPE_CONFIG); 
//								break;
//						}
//						IAPVarTypeStruct_Ptr->IapErrFlag = 1;                                                                  //升级错误标志置一
//						Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级配置失败，配置文件头、版本等错误\n");
//					}
				}
				else if(args->block>CFG_MAX_BLOCK)                            //如果超过配置最大内存范围32K数据 //文件大小错误
				{
					switch(IAPVarTypeStruct_Ptr->IapType)
					{
						case IAPTFTPWRITE:		//回复升级块错误
							LOGIC_Config_AckState(IAP_Error_Block, (uint8_t *)ip, (uint16_t)port);  
							break;  
						case IAPTFTPREAD:
							CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Error_Block, (uint8_t *)ip, (uint16_t)port, DATATYPE_CONFIG);
							break;
					}
					IAPVarTypeStruct_Ptr->IapErrFlag = 1; 
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级配置失败，超出最大块数\n");
				}
				break;
		}

		switch(IAPVarTypeStruct_Ptr->IapFileType)              //类型IAP_VarEx.tftp_type
		{
			case DATATYPE_CONFIG:                    //配置
			case DATATYPE_IAP:                       //固件
				args->block++;                                                             //块增加
				/*BLV_C1 先将数据保存到SRAM中，校验通过后便将数据存入Flash中*/
			
				SRAM_Write_Buff(data_buffer,512,IAPVarTypeStruct_Ptr->FlashWriteAddress);
				IAPVarTypeStruct_Ptr->FlashWriteAddress += count*4;
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"写入地址：%08X,写入数据: count=%d,byte：%d", IAPVarTypeStruct_Ptr->FlashWriteAddress, count, (pkt_buf_len - TFTP_DATA_PKT_HDR_LEN));
			
				(args->tot_bytes) += (pkt_buf_len - TFTP_DATA_PKT_HDR_LEN);         //总数字节数  除去报文头
				break;
		}
	}
	else if (IAP_tftp_extract_block((char *)pkt_buf) == (args->block + 1))         //块号，对的上    
	{
		args->block++;                                                          //更新我们的块号，以匹配接收到的块号
	}

	IAP_tftp_send_ack_packet(s, ip_addr, Port, args->block);   //对每次传数据包的回复，传套接字 地址 端口和块号 
	
	if( (IAPVarTypeStruct_Ptr->NewIapFlag != 0x01) && (args->block != 0x00) && (args->block % 50 == 0x00) && (IAPVarTypeStruct_Ptr->BlockSize != args->block) ){
		/*2025-02-14 新增向云端服务器上报云端升级进度 */
		Cloud_IAP_Plan_SendPack(args,IAPVarTypeStruct_Ptr,IAPPlan_State_Underway);		//升级中。。。
	}

	/*当前不是BLV_Cx升级流程，并且当前是最后一块数据，便执行以下校验文件操作*/
	if((IAPVarTypeStruct_Ptr->NewIapFlag != 0x01) && (IAPVarTypeStruct_Ptr->BlockSize == args->block))       
	{
		Cloud_IAP_Plan_SendPack(args,IAPVarTypeStruct_Ptr,IAPPlan_State_Checking);		//升级传输完成，校验中。。。
		
		CH57xNET_SocketClose(s, TCP_CLOSE_NORMAL);                     //就关闭65535-文件传输套接字
		CH57xNET_SocketClose(net_info.SocketId[1], TCP_CLOSE_NORMAL);  //关闭69-TFTP服务套接字
		
		Udp_IAP_sta = STA_INIT;        //将升级服务状态置为需要初始化
		switch(IAPVarTypeStruct_Ptr->IapFileType)
		{
			case DATATYPE_IAP:
				{
					char md5[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
					
					/*校验SRAM中的数据内容*/
					MD5Digest_SRAM(SRAM_IAP_APP_FILE_ADDRESS, (IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_APP_FILE_ADDRESS),(char *)&md5[0]);
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"falsh写入总长度：%dByte", (IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_APP_FILE_ADDRESS));

					if(0==bytes_cmp((uint8_t*)&md5[0], &IAPVarTypeStruct_Ptr->Md5[0], 16))   //IAP_VarEx.md5
					{
						//文件正确，此处将已经写入SRAM的APP文件，写入FLASH
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级成功，Md5正确");
						switch(IAPVarTypeStruct_Ptr->IapType)
						{
							case IAPTFTPWRITE: 	//本地网络升级状态为完成,保存参数
								Dbg_Println(DBG_BIT_NET_STATUS_bit,"记录局域网升级成功状态..");
								SRAM_Write_Byte(IAP_STATE_COMPLETE, SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);
								LOG_LogicInfo_DebugRecord("记录局域网升级成功状态..");
								break;                
							case IAPTFTPREAD: 		//云端网络升级
								Dbg_Println(DBG_BIT_NET_STATUS_bit,"记录云端升级成功状态..");
								LOG_LogicInfo_DebugRecord("记录云端升级成功状态..");
								SRAM_Write_Byte(CLOUD_IAP_TFTP_STATE_COMPLETE, SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);
								break;              
						}
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"将APP写入Flash中..");
						
						Cloud_IAP_Plan_SendPack(args,IAPVarTypeStruct_Ptr,IAPPlan_State_CheckSucc);		//升级传输完成，校验中。。。
		
						Flash_APPDATA_Erase();		//擦除Flash
						
						for(i = 0;i<IAPVarTypeStruct_Ptr->BlockSize;i++)
						{
							WDT_Feed();
							temp_var = SRAM_IAP_APP_FILE_ADDRESS+i*512;
							SRAM_Read_Buff(args->data,512,SRAM_IAP_APP_FILE_ADDRESS+i*512);
							Flash_Write(args->data,512,IAP_RUN_START_PAGE_ADDRESS_FALSH+i*512);
						}
						
						for(i=0;i<512;i++)	args->data[i] = 0x00;
						/*向特征区内保存数据*/
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"args->block:%d",args->block);
						/*计算APP的CRC校验值 Start_BootLoader*/
						temp_var = IAP_RUN_START_PAGE_ADDRESS_FALSH;
						CRC_Num = IAPVarTypeStruct_Ptr->BlockSize % 4;
						if(CRC_Num == 0x00)
						{
							CRC_Num = IAPVarTypeStruct_Ptr->BlockSize / 4;
						}else {
							CRC_Num = IAPVarTypeStruct_Ptr->BlockSize / 4;
							CRC_Num += 1;
						}
						for(i = 0;i<CRC_Num;i++)
						{
							WDT_Feed();
//							Flash_Read(data_buffer ,App_CRC_Size,temp_var);
//							CRC_Val = NetCRC16_2(data_buffer,App_CRC_Size);
//							CRC_Val = FlashData_NetCRC16(temp_var, data_buffer, App_CRC_Size);
							CRC_Val = FlashData_NetCRC16(temp_var, App_CRC_Size);
							args->data[F_App_CRC+i*2] = (CRC_Val>>8) & 0xFF;
							args->data[F_App_CRC+i*2+1] = CRC_Val & 0xFF;
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"SRAM_ADDR: %08X, Block:%ld ,crc_val:%04X , data:%02X%02X",temp_var,i,CRC_Val,args->data[F_App_CRC+i*2],args->data[F_App_CRC+i*2+1]);
							temp_var += App_CRC_Size;
							if(temp_var >= IAP_RUN_END_PAGE_ADDRESS_FALSH) break;
						}
						
						CRC_Num *= 2;
						args->data[F_App_CRC_Len] |= CRC_Num & 0xFF;
						args->data[F_App_CRC_Len+1] |= (CRC_Num>>8) & 0xFF;
						
						temp_var = IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_APP_FILE_ADDRESS + IAP_RUN_START_PAGE_ADDRESS_FALSH;
						
						args->data[F_App_Start_Addr] |= IAP_RUN_START_PAGE_ADDRESS_FALSH & 0xFF;
						args->data[F_App_Start_Addr+1] |= (IAP_RUN_START_PAGE_ADDRESS_FALSH >> 8) & 0xFF;
						args->data[F_App_Start_Addr+2] |= (IAP_RUN_START_PAGE_ADDRESS_FALSH >> 16) & 0xFF;
						args->data[F_App_Start_Addr+3] |= (IAP_RUN_START_PAGE_ADDRESS_FALSH >> 24) & 0xFF;
						args->data[F_App_End_Addr] |= temp_var & 0xFF;
						args->data[F_App_End_Addr+1] |= (temp_var >> 8) & 0xFF;
						args->data[F_App_End_Addr+2] |= (temp_var >> 16) & 0xFF;
						args->data[F_App_End_Addr+3] |= (temp_var >> 24) & 0xFF;
						args->data[F_App_Flag] = App_Procedure_Ready;		//保存APP标志位置一
						
						i = NetCRC16_2(&args->data[2],510);
						
						args->data[F_App_Check] |= i & 0xFF;
						args->data[F_App_Check+1] |= (i>>8) & 0xFF;
						
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"APP CRC:%02X%02X",args->data[F_App_Check+1],args->data[F_App_Check]);
						
						Flash_Write(args->data,512,Flash_IAP_FEATURE_ADDRESS);		//保存特征区数据
						
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"NET UPdate SUCC..");
						DelayMs(10);
								
						IAPVarTypeStruct_Ptr->IapState = IAPFINISH;
						if(IAPVarTypeStruct_Ptr != NULL)
						free(IAPVarTypeStruct_Ptr);
						IAPVarTypeStruct_Ptr = NULL;
						
						if(tftp_args != NULL)
						free(tftp_args);
						tftp_args = NULL;
						
						WDT_Feed();		//防止看门狗复位
						
						Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"固件网络升级复位!");
						LOG_LogicInfo_DebugRecord("固件网络升级复位");
						
						SYS_ResetExecute();			//直接复位
						
					}
					else
					{
						switch(IAPVarTypeStruct_Ptr->IapType)
						{
							case IAPTFTPWRITE://IAP_AckState(IAP_Error_MD5, (uint8_t *)ip, (uint16_t)port);  break;  //回复Md5错误
								IAP_AckState(IAP_Error_MD5, (uint8_t *)ip_addr, (uint16_t)sever_port);  	//回复Md5错误
								break;  
							case IAPTFTPREAD:
								CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Error_MD5, (uint8_t *)ip, (uint16_t)port, DATATYPE_IAP);
								break;
						}
						IAPVarTypeStruct_Ptr->IapErrFlag = 1;
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级失败，Md5错误:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X%02X,%02X,%02X,%02X,%02X,%02X",md5[0],md5[1],md5[2],md5[3],md5[4],md5[5],md5[6],md5[7],md5[8],md5[9],md5[10],md5[11],md5[12],md5[13],md5[14],md5[15]);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP Md5:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",\
							IAPVarTypeStruct_Ptr->Md5[0],IAPVarTypeStruct_Ptr->Md5[1],\
							IAPVarTypeStruct_Ptr->Md5[2],IAPVarTypeStruct_Ptr->Md5[3],\
							IAPVarTypeStruct_Ptr->Md5[4],IAPVarTypeStruct_Ptr->Md5[5],\
							IAPVarTypeStruct_Ptr->Md5[6],IAPVarTypeStruct_Ptr->Md5[7],\
							IAPVarTypeStruct_Ptr->Md5[8],IAPVarTypeStruct_Ptr->Md5[9],\
							IAPVarTypeStruct_Ptr->Md5[10],IAPVarTypeStruct_Ptr->Md5[11],\
							IAPVarTypeStruct_Ptr->Md5[12],IAPVarTypeStruct_Ptr->Md5[13],\
							IAPVarTypeStruct_Ptr->Md5[14],IAPVarTypeStruct_Ptr->Md5[15]);
					}
				}
				break;
			case DATATYPE_CONFIG:
				{
					
					char md5[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
					/*校验SRAM中的数据内容*/
					MD5Digest_SRAM(SRAM_IAP_LOGIC_DataStart_ADDRESS, (IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_LOGIC_DataStart_ADDRESS),(char *)&md5[0]); 
					if(0==bytes_cmp((uint8_t*)&md5[0],(uint8_t*)&IAPVarTypeStruct_Ptr->Md5[0],16))
					{
						//文件正确，此处应该讲数据存储逻辑文件存储到Flash中
						uint32_t data_size = IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_LOGIC_DataStart_ADDRESS;
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级成功，Md5正确 Len:%08X",data_size);
						switch(IAPVarTypeStruct_Ptr->IapType)
						{
							case IAPTFTPWRITE:		//回复发送完成
								Dbg_Println(DBG_BIT_NET_STATUS_bit,"记录逻辑文件写入成功状态..");
								LOGIC_Config_AckState(IAP_Finish, (uint8_t *)ip, (uint16_t)sever_port);  
								break;  
							case IAPTFTPREAD:
								Dbg_Println(DBG_BIT_NET_STATUS_bit,"记录逻辑文件读取成功状态..");
								CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Finish, (uint8_t *)ip, (uint16_t)sever_port, DATATYPE_CONFIG);
								break;
						}
						
						Cloud_IAP_Plan_SendPack(args,IAPVarTypeStruct_Ptr,IAPPlan_State_CheckSucc);		//升级传输完成，校验中。。。
						
						/*2022-09-14 进行修改
						*/
						Flash_LOGICDATA_Erase();
						//将文件写入到Flash中,暂时不需要
						for(i = 0;i<IAPVarTypeStruct_Ptr->BlockSize;i++)
						{
							WDT_Feed();
							temp_var = SRAM_IAP_LOGIC_DataStart_ADDRESS+i*512;
							SRAM_Read_Buff(args->data,512,SRAM_IAP_LOGIC_DataStart_ADDRESS+i*512);
							Flash_Write(args->data,512,FLASH_LOGIC_DataStart_ADDRESS+i*512);
						}
						
						//同时将MD5值,和文件块号保存到Flash中
						
						args->data[0] = 0x01;
						args->data[1] = 0x00;
						args->data[2] = 0x06;
						args->data[3] = 0xCC;
						
						args->data[4] = data_size & 0xFF;
						args->data[5] = (data_size >> 8) & 0xFF;
						args->data[6] = (data_size >> 16) & 0xFF;
						args->data[7] = (data_size >> 24) & 0xFF;
						
						memcpy(&args->data[8],IAPVarTypeStruct_Ptr->Md5,16);
						
						Flash_Write(args->data,24,FLASH_LOGIC_DataFlag_ADDRESS);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"将逻辑文件写入到Flash中");

						IAPVarTypeStruct_Ptr->IapState = IAPFINISH;
						if(IAPVarTypeStruct_Ptr != NULL)
						free(IAPVarTypeStruct_Ptr);
						IAPVarTypeStruct_Ptr = NULL;
						
						if(tftp_args != NULL)
						free(tftp_args);
						tftp_args = NULL;
						
						WDT_Feed();		//防止看门狗复位
						
						Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"配置网络升级复位!");
						LOG_LogicInfo_DebugRecord("配置网络升级复位");
						
						SYS_ResetExecute();			//直接复位
					}
					else 
					{
						switch(IAPVarTypeStruct_Ptr->IapType)
						{
							case IAPTFTPWRITE:	//回复发送完成
								LOGIC_Config_AckState(IAP_Error_MD5, (uint8_t *)ip_addr, (uint16_t)sever_port);  
								break;  
							case IAPTFTPREAD:
								CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Error_MD5, (uint8_t *)ip, (uint16_t)sever_port, DATATYPE_CONFIG);
								break;
						}
						IAPVarTypeStruct_Ptr->IapErrFlag = 1;
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级配置失败，Md5错误:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X%02X,%02X,%02X,%02X,%02X,%02X",md5[0],md5[1],md5[2],md5[3],md5[4],md5[5],md5[6],md5[7],md5[8],md5[9],md5[10],md5[11],md5[12],md5[13],md5[14],md5[15]);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP Md5:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",\
							IAPVarTypeStruct_Ptr->Md5[0],IAPVarTypeStruct_Ptr->Md5[1],\
							IAPVarTypeStruct_Ptr->Md5[2],IAPVarTypeStruct_Ptr->Md5[3],\
							IAPVarTypeStruct_Ptr->Md5[4],IAPVarTypeStruct_Ptr->Md5[5],\
							IAPVarTypeStruct_Ptr->Md5[6],IAPVarTypeStruct_Ptr->Md5[7],\
							IAPVarTypeStruct_Ptr->Md5[8],IAPVarTypeStruct_Ptr->Md5[9],\
							IAPVarTypeStruct_Ptr->Md5[10],IAPVarTypeStruct_Ptr->Md5[11],\
							IAPVarTypeStruct_Ptr->Md5[12],IAPVarTypeStruct_Ptr->Md5[13],\
							IAPVarTypeStruct_Ptr->Md5[14],IAPVarTypeStruct_Ptr->Md5[15]);
					}
				}
				break;
			default:
				IAPVarTypeStruct_Ptr->IapErrFlag = 1;
				break ;
		}
		
	}
	else
	{
		return ;
	}
	
	if(1 == IAPVarTypeStruct_Ptr->IapErrFlag)              //如果有错误
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级错误，Md5错误");
		
		CH57xNET_SocketClose(s, TCP_CLOSE_NORMAL);                     	//就关闭65535-文件传输套接字
		CH57xNET_SocketClose(net_info.SocketId[1], TCP_CLOSE_NORMAL);  	//关闭69-TFTP服务套接字
		Udp_IAP_sta = STA_INIT;        									//将升级服务状态置为需要初始化
		IAPVarTypeStruct_Ptr->IapErrFlag = 0;

		if(IAPVarTypeStruct_Ptr != NULL)	free(IAPVarTypeStruct_Ptr);
		IAPVarTypeStruct_Ptr = NULL;
		
		if(tftp_args != NULL)	free(tftp_args);
		tftp_args = NULL;
	}else{
		
	}
}

/*******************************************************************************
* Function Name  : Udp_Internal_BLVIAPCheck_Process
* Description    : BLV_Cx系列升级校验文件命令 - 
* Input     	: 
* Return         : None
*******************************************************************************/
uint8_t Udp_Internal_BLVIAPCheck_Process(uint8_t* data,uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	static uint8_t App_Check = 0;		//APP校验标志位
	uint8_t rev = 0,result = 0x00;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	UINT32 len = HEAD_LEN+3;
	uint8_t back_data[len];
	memset(back_data,0,sizeof(back_data));
	
	uint16_t i=0,CRC_Num=0,CRC_Val=0;
	uint32_t temp_var=0;
	uint16_t frame_id = 0;
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;
	tftp_connection_args *args = (tftp_connection_args *)tftp_args;
	
	if(IAPVarTypeStruct_Ptr != NULL)
	{
		/*当前不是BLV_Cx升级流程，并且当前是最后一块数据，便执行以下校验文件操作*/
		if((IAPVarTypeStruct_Ptr->NewIapFlag == 0x01) && (IAPVarTypeStruct_Ptr->BlockSize == args->block))       
		{
			CH57xNET_SocketClose(net_info.SocketId[2], TCP_CLOSE_NORMAL);   //就关闭65535-文件传输套接字
			CH57xNET_SocketClose(net_info.SocketId[1], TCP_CLOSE_NORMAL);  	//关闭69-TFTP服务套接字
			Udp_IAP_sta = STA_INIT;        //将升级服务状态置为需要初始化
			switch(IAPVarTypeStruct_Ptr->IapFileType)
			{
				case DATATYPE_IAP:
					{
						char md5[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
						
						/*校验SRAM中的数据内容*/
						MD5Digest_SRAM(SRAM_IAP_APP_FILE_ADDRESS, (IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_APP_FILE_ADDRESS),(char *)&md5[0]);
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"falsh写入总长度：%dByte", (IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_APP_FILE_ADDRESS));

						if(0==bytes_cmp((uint8_t*)&md5[0], &IAPVarTypeStruct_Ptr->Md5[0], 16))   //IAP_VarEx.md5
						{
							//文件正确，此处将已经写入SRAM的APP文件，写入FLASH
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级成功，Md5正确");
							switch(IAPVarTypeStruct_Ptr->IapType)
							{
								case IAPTFTPWRITE: 	//本地网络升级状态为完成,保存参数
									Dbg_Println(DBG_BIT_NET_STATUS_bit,"记录局域网升级成功状态..");
									SRAM_Write_Byte(IAP_STATE_COMPLETE, SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);      
									break;                
								case IAPTFTPREAD: 		//云端网络升级
									Dbg_Println(DBG_BIT_NET_STATUS_bit,"记录云端升级成功状态..");
									SRAM_Write_Byte(CLOUD_IAP_TFTP_STATE_COMPLETE, SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);
									break;              
							}
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"将APP写入Flash中..");
							Flash_APPDATA_Erase();		//擦除Flash
							
							for(i = 0;i<IAPVarTypeStruct_Ptr->BlockSize;i++)
							{
								WDT_Feed();
								temp_var = SRAM_IAP_APP_FILE_ADDRESS+i*512;
								SRAM_Read_Buff(args->data,512,SRAM_IAP_APP_FILE_ADDRESS+i*512);
								Flash_Write(args->data,512,IAP_RUN_START_PAGE_ADDRESS_FALSH+i*512);
							}
							
							for(i=0;i<512;i++)	args->data[i] = 0x00;
							/*向特征区内保存数据*/
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"args->block:%d",args->block);
							/*计算APP的CRC校验值 Start_BootLoader*/
							temp_var = IAP_RUN_START_PAGE_ADDRESS_FALSH;
							CRC_Num = IAPVarTypeStruct_Ptr->BlockSize % 4;
							if(CRC_Num == 0x00)
							{
								CRC_Num = IAPVarTypeStruct_Ptr->BlockSize / 4;
							}else {
								CRC_Num = IAPVarTypeStruct_Ptr->BlockSize / 4;
								CRC_Num += 1;
							}
							for(i = 0;i<CRC_Num;i++)
							{
								WDT_Feed();

								CRC_Val = FlashData_NetCRC16(temp_var, App_CRC_Size);
								args->data[F_App_CRC+i*2] = (CRC_Val>>8) & 0xFF;
								args->data[F_App_CRC+i*2+1] = CRC_Val & 0xFF;
								Dbg_Println(DBG_BIT_NET_STATUS_bit,"SRAM_ADDR: %08X, Block:%ld ,crc_val:%04X , data:%02X%02X",temp_var,i,CRC_Val,args->data[F_App_CRC+i*2],args->data[F_App_CRC+i*2+1]);
								temp_var += App_CRC_Size;
								if(temp_var >= IAP_RUN_END_PAGE_ADDRESS_FALSH) break;
							}
							
							CRC_Num *= 2;
							args->data[F_App_CRC_Len] |= CRC_Num & 0xFF;
							args->data[F_App_CRC_Len+1] |= (CRC_Num>>8) & 0xFF;
							
							temp_var = IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_APP_FILE_ADDRESS + IAP_RUN_START_PAGE_ADDRESS_FALSH;
							
							args->data[F_App_Start_Addr] |= IAP_RUN_START_PAGE_ADDRESS_FALSH & 0xFF;
							args->data[F_App_Start_Addr+1] |= (IAP_RUN_START_PAGE_ADDRESS_FALSH >> 8) & 0xFF;
							args->data[F_App_Start_Addr+2] |= (IAP_RUN_START_PAGE_ADDRESS_FALSH >> 16) & 0xFF;
							args->data[F_App_Start_Addr+3] |= (IAP_RUN_START_PAGE_ADDRESS_FALSH >> 24) & 0xFF;
							args->data[F_App_End_Addr] |= temp_var & 0xFF;
							args->data[F_App_End_Addr+1] |= (temp_var >> 8) & 0xFF;
							args->data[F_App_End_Addr+2] |= (temp_var >> 16) & 0xFF;
							args->data[F_App_End_Addr+3] |= (temp_var >> 24) & 0xFF;
							args->data[F_App_Flag] = App_Procedure_Ready;		//保存APP标志位置一
							
							i = NetCRC16_2(&args->data[2],510);
							
							args->data[F_App_Check] |= i & 0xFF;
							args->data[F_App_Check+1] |= (i>>8) & 0xFF;
							
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"APP CRC:%02X%02X",args->data[F_App_Check+1],args->data[F_App_Check]);
							
							Flash_Write(args->data,512,Flash_IAP_FEATURE_ADDRESS);		//保存特征区数据
							
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"NET UPdate SUCC..");
							DelayMs(10);
									
							IAPVarTypeStruct_Ptr->IapState = IAPFINISH;
							if(IAPVarTypeStruct_Ptr != NULL)
							free(IAPVarTypeStruct_Ptr);
							IAPVarTypeStruct_Ptr = NULL;
							
							if(tftp_args != NULL)
							free(tftp_args);
							tftp_args = NULL;
							
							WDT_Feed();		//防止看门狗复位
							
							result = 0x01;		//文件校验成功
							App_Check = 0x11;	//校验完成，并成功
						}
						else
						{				
							result = 0x02;		//文件校验错误
							IAPVarTypeStruct_Ptr->IapErrFlag = 1;
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级失败，Md5错误:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X%02X,%02X,%02X,%02X,%02X,%02X",md5[0],md5[1],md5[2],md5[3],md5[4],md5[5],md5[6],md5[7],md5[8],md5[9],md5[10],md5[11],md5[12],md5[13],md5[14],md5[15]);
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP Md5:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",\
								IAPVarTypeStruct_Ptr->Md5[0],IAPVarTypeStruct_Ptr->Md5[1],\
								IAPVarTypeStruct_Ptr->Md5[2],IAPVarTypeStruct_Ptr->Md5[3],\
								IAPVarTypeStruct_Ptr->Md5[4],IAPVarTypeStruct_Ptr->Md5[5],\
								IAPVarTypeStruct_Ptr->Md5[6],IAPVarTypeStruct_Ptr->Md5[7],\
								IAPVarTypeStruct_Ptr->Md5[8],IAPVarTypeStruct_Ptr->Md5[9],\
								IAPVarTypeStruct_Ptr->Md5[10],IAPVarTypeStruct_Ptr->Md5[11],\
								IAPVarTypeStruct_Ptr->Md5[12],IAPVarTypeStruct_Ptr->Md5[13],\
								IAPVarTypeStruct_Ptr->Md5[14],IAPVarTypeStruct_Ptr->Md5[15]);
							
							App_Check = 0x12;	//校验完成，错误
						}
					}
					break;
				case DATATYPE_CONFIG:
					{
						char md5[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
						/*校验SRAM中的数据内容*/
						MD5Digest_SRAM(SRAM_IAP_LOGIC_DataStart_ADDRESS, (IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_LOGIC_DataStart_ADDRESS),(char *)&md5[0]); 
						if(0==bytes_cmp((uint8_t*)&md5[0],(uint8_t*)&IAPVarTypeStruct_Ptr->Md5[0],16))
						{
							//文件正确，此处应该讲数据存储逻辑文件存储到Flash中
							uint32_t data_size = IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_LOGIC_DataStart_ADDRESS;
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级成功，Md5正确 Len:%08X",data_size);
							switch(IAPVarTypeStruct_Ptr->IapType)
							{
								case IAPTFTPWRITE:		//回复发送完成
									Dbg_Print(DBG_BIT_NET_STATUS_bit,"记录逻辑文件写入成功状态..");
									LOGIC_Config_AckState(IAP_Finish, (uint8_t *)ip, (uint16_t)sever_port);  
									SRAM_Write_Byte(IAP_STATE_COMPLETE, SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);  
									break;  
								case IAPTFTPREAD:
									Dbg_Print(DBG_BIT_NET_STATUS_bit,"记录逻辑文件读取成功状态.");
									CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Finish, (uint8_t *)ip, (uint16_t)sever_port, DATATYPE_CONFIG);
									SRAM_Write_Byte(CLOUD_IAP_TFTP_STATE_COMPLETE, SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);  
									break;
							}
							
							
							/*目前该区域没有合适的空间进行存储，只有使用日志空间进行存储，Flash中的日志空间目前没有使用
								
							*/
							Flash_LOGICDATA_Erase();
							//将文件写入到Flash中,暂时不需要
							for(i = 0;i<IAPVarTypeStruct_Ptr->BlockSize;i++)
							{
								WDT_Feed();
								temp_var = SRAM_IAP_LOGIC_DataStart_ADDRESS+i*512;
								SRAM_Read_Buff(args->data,512,SRAM_IAP_LOGIC_DataStart_ADDRESS+i*512);
								Flash_Write(args->data,512,FLASH_LOGIC_DataStart_ADDRESS+i*512);
							}
							
							//同时将MD5值,和文件块号保存到Flash中
							
							args->data[0] = 0x01;
							args->data[1] = 0x00;
							args->data[2] = 0x06;
							args->data[3] = 0xCC;
							
							args->data[4] = data_size & 0xFF;
							args->data[5] = (data_size >> 8) & 0xFF;
							args->data[6] = (data_size >> 16) & 0xFF;
							args->data[7] = (data_size >> 24) & 0xFF;
							
							memcpy(&args->data[8],IAPVarTypeStruct_Ptr->Md5,16);
							
							Flash_Write(args->data,24,FLASH_LOGIC_DataFlag_ADDRESS);
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"将逻辑文件写入到Flash中");

							IAPVarTypeStruct_Ptr->IapState = IAPFINISH;
							if(IAPVarTypeStruct_Ptr != NULL)
							free(IAPVarTypeStruct_Ptr);
							IAPVarTypeStruct_Ptr = NULL;
							
							if(tftp_args != NULL)
							free(tftp_args);
							tftp_args = NULL;
							
							result = 0x01;		//文件校验成功
							App_Check = 0x11;	//校验完成，并成功
						}
						else 
						{
	//						switch(IAPVarTypeStruct_Ptr->IapType)
	//						{
	//							case IAPTFTPWRITE:	//回复发送完成
	//								LOGIC_Config_AckState(IAP_Error_MD5, (uint8_t *)ip, (uint16_t)sever_port);  
	//								break;  
	//							case IAPTFTPREAD:
	//								CLOUD_IAP_AckState(CLOUD_IAP_Cmd, IAP_Error_MD5, (uint8_t *)ip, (uint16_t)sever_port, DATATYPE_CONFIG);
	//								break;
	//						}
							result = 0x02;		//文件校验错误
							App_Check = 0x12;	//校验完成，错误
							IAPVarTypeStruct_Ptr->IapErrFlag = 1;
							
							
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"逻辑文件长度:%d,地址:%08X",IAPVarTypeStruct_Ptr->FlashWriteAddress - SRAM_IAP_LOGIC_DataStart_ADDRESS,IAPVarTypeStruct_Ptr->FlashWriteAddress);
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级配置失败，Md5错误:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X%02X,%02X,%02X,%02X,%02X,%02X",md5[0],md5[1],md5[2],md5[3],md5[4],md5[5],md5[6],md5[7],md5[8],md5[9],md5[10],md5[11],md5[12],md5[13],md5[14],md5[15]);
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP Md5:%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",\
								IAPVarTypeStruct_Ptr->Md5[0],IAPVarTypeStruct_Ptr->Md5[1],\
								IAPVarTypeStruct_Ptr->Md5[2],IAPVarTypeStruct_Ptr->Md5[3],\
								IAPVarTypeStruct_Ptr->Md5[4],IAPVarTypeStruct_Ptr->Md5[5],\
								IAPVarTypeStruct_Ptr->Md5[6],IAPVarTypeStruct_Ptr->Md5[7],\
								IAPVarTypeStruct_Ptr->Md5[8],IAPVarTypeStruct_Ptr->Md5[9],\
								IAPVarTypeStruct_Ptr->Md5[10],IAPVarTypeStruct_Ptr->Md5[11],\
								IAPVarTypeStruct_Ptr->Md5[12],IAPVarTypeStruct_Ptr->Md5[13],\
								IAPVarTypeStruct_Ptr->Md5[14],IAPVarTypeStruct_Ptr->Md5[15]);
						}
					}
					break;
				default:
					result = 0x10;		//其他错误
					App_Check = 0x10;	//其他错误
					IAPVarTypeStruct_Ptr->IapErrFlag = 1;
					break ;
			}
			
		}else if((IAPVarTypeStruct_Ptr->NewIapFlag == 0x01) && (IAPVarTypeStruct_Ptr->BlockSize != args->block))
		{
			/*文件还没接收完毕*/
			result = 0x03;		//文件未接收完成
			App_Check = 0x13;	//其他错误
		}else {
			result = 0x10;		//其他错误
			
		}
		
		if(1 == IAPVarTypeStruct_Ptr->IapErrFlag)              //如果有错误
		{
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"升级错误 - IapErrFlag");
			CH57xNET_SocketClose(net_info.SocketId[2], TCP_CLOSE_NORMAL);   //就关闭65535-文件传输套接字
			CH57xNET_SocketClose(net_info.SocketId[1], TCP_CLOSE_NORMAL);  	//关闭69-TFTP服务套接字
			Udp_IAP_sta = STA_INIT;        									//将升级服务状态置为需要初始化
			IAPVarTypeStruct_Ptr->IapErrFlag = 0;

			if(IAPVarTypeStruct_Ptr != NULL)	free(IAPVarTypeStruct_Ptr);
			IAPVarTypeStruct_Ptr = NULL;
			
			if(tftp_args != NULL)	free(tftp_args);
			tftp_args = NULL;
		}
	}else {
		/*本次升级资源已释放，返回释放前结果*/
		if(App_Check != 0x00)
		{
			if(App_Check == 0x10)
			{
				/*之前校验过，其他错误*/
				result = 0x10;
			}else if(App_Check == 0x11)
			{
				/*之前校验过，成功*/
				result = 0x01;
			}else if(App_Check == 0x12)
			{
				/*之前校验过，失败*/
				result = 0x02;
			}else if(App_Check == 0x13)
			{
				/*之前校验过，未接收完毕*/
				result = 0x03;
			}
		}
	}
	
	UDP_Add_Header(back_data,In_BLVIAPCheck_Cmd,len,frame_id);
	back_data[UDP_PackData] = result;			
	NetCRC16(back_data,len);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s --------",__func__);
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0],back_data,&len,ip,port);
	
	return rev;
	
}

/*******************************************************************************
* Function Name  : Udp_Internal_BLVIAPCheck_Process
* Description    : BLV_Cx系列升级校验文件命令 - 
* Input     	: 
* Return         : None
*******************************************************************************/
uint8_t Udp_Internal_BLVIAPJUMP_Process(uint8_t* data,uint16_t DataLen, uint8_t *ip,uint16_t port)
{
	uint8_t rev = 0,result = 0x02;
	uint16_t data_crc = data[DataLen-2] + (data[DataLen-1] << 8);
	if(NetCRC16_2(data,DataLen-2) != data_crc) return 0xF0;
	
	UINT32 len = HEAD_LEN+3;
	uint8_t back_data[len];
	memset(back_data,0,sizeof(back_data));
	
	uint16_t frame_id = 0;
	frame_id = data[FRAME_NO_OFFSET];
	frame_id |= data[FRAME_NO_OFFSET + 1] << 8;

	switch(data[UDP_PackData])
	{
		case 0x01:
			result = 0x01;
			break;
		case 0x02:
			result = 0x01;
			break;
	}

	
	UDP_Add_Header(back_data,In_BLVIAPJump_Cmd,len,frame_id);
	back_data[UDP_PackData] = result;			
	NetCRC16(back_data,len);
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"%s -------",__func__);
	
	LOG_LogicInfo_DebugRecord("网络升级跳转命令回复");
	
	rev = CH57xNET_SocketUdpSendTo(net_info.SocketId[0],back_data,&len,ip,port);
	
	DelayMs(20);
	
	WDT_Feed();		//防止看门狗提前复位
	
	/*UDP 发送完成后500ms复位 - 待测试*/
	switch(data[UDP_PackData])
	{
		case 0x01:	//软件复位
			WWDG_ResetCfg(DISABLE);
			DelayMs(100);
			SYS_ResetExecute();			//直接复位
			break;
		case 0x02:	//看门狗复位
			DelayMs(1000);
			break;
		
	}
	
	return rev;
}


/*************************
**函数名：TFTP_FILE_Analysis
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：TFTP文件传输的网络套接字接收解析处理      
**返回值：无        
*调用方式：TFTP文件传输的网络套接字接收回调中调用
**
************************/
void TFTP_FILE_Analysis(UINT8 *data, UINT32 len, uint8_t* ip, uint16_t port)
{
	tftp_opcode op;
	op = IAP_tftp_decode_op((char *)data);
	if (op == TFTP_DATA)    //TFTP文件数据
	{
		IAP_wrq_recv_callback((void *)tftp_args, net_info.SocketId[2], data, len, ip, port);  //对tftp文件传输的写入，数据包回复，以及数据包判断
	}
	else if(op == TFTP_ACK)  //TFTP的ACK,此处是写日志的场景才会出现
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP的ACK,此处是写日志");
//		TFTP_Read_Journal_CallBack(SOCK_TFTP_FILE, buff_file, len_file, ip_file, port_file);
	}
}

/*******************************************************************************
* Function Name  : IAP_tftp_process_write
* Description    : IAP TFTP 写命令处理函数
* Input          : 
	s 		: 套接字ID号
	to_ip 	: 接收的IP
	to_port	：接收的端口
* Return         : None
*******************************************************************************/
int IAP_tftp_process_write(uint8_t s, uint8_t* to_ip, int to_port)
{
	tftp_args->op = TFTP_WRQ;
	memcpy(&tftp_args->to_ip[0],to_ip,4);
	tftp_args->to_port = to_port;

	tftp_args->block = 0;
	tftp_args->tot_bytes = 0;

	IAPVarTypeStruct_Ptr->TotalCount =0;
	IAPVarTypeStruct_Ptr->IapErrFlag = 0;
	
	/*BLV_C1 -- 擦除Flash数据，还是在验证完数据之后，再擦除同时将SRAM中的数据写入flash中*/
	if(IAPVarTypeStruct_Ptr->IapFileType == DATATYPE_IAP)
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"设置升级文件写入地址");
		IAPVarTypeStruct_Ptr->FlashWriteAddress = SRAM_IAP_APP_FILE_ADDRESS;	//设置写地址 - 数据先保存在SRAM中
	}
	else if(IAPVarTypeStruct_Ptr->IapFileType == DATATYPE_CONFIG)
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"设置逻辑配置写入地址");
		IAPVarTypeStruct_Ptr->FlashWriteAddress = SRAM_IAP_LOGIC_DataStart_ADDRESS;  //设置写地址 - 数据先保存在SRAM中
	}
	else
	{
		return 1;
	}
	
	IAP_tftp_send_ack_packet(s, to_ip, to_port, tftp_args->block);
	return 0;
}

uint8_t UDP_Heart_falg = 0;
void TFTP_CMD_ACK(uint8_t* ip, uint16_t port)
{
	switch(IAPVarTypeStruct_Ptr->TftpStart)
	{
		case TFTPWRITESTART:
			UDP_Heart_falg = 1;
			if(tftp_args == NULL)
			{
				tftp_args = (tftp_connection_args*)malloc(sizeof(tftp_connection_args));    //分配空间
				memset(tftp_args, 0, sizeof(tftp_connection_args));
			}
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP回复写文件指令...");
			IAP_tftp_process_write(net_info.SocketId[2], ip, port);   //回复升级  写文件指令
			IAPVarTypeStruct_Ptr->TftpStart = 0x00;
			break;
		case TFTPREADSTART:
			UDP_Heart_falg = 1;
			if(tftp_args == NULL)
			{
				tftp_args = (tftp_connection_args*)malloc(sizeof(tftp_connection_args));    //分配空间
				memset(tftp_args, 0, sizeof(tftp_connection_args));
			}
			
			Cloud_IAP_Plan_SendPack(tftp_args,IAPVarTypeStruct_Ptr,IAPPlan_State_Starting);		//升级开始
					
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP读文件指令发送 port:%d...",IAPVarTypeStruct_Ptr->TFTP_Port);
			IAP_tftp_process_read(net_info.SocketId[2], ip, IAPVarTypeStruct_Ptr->TFTP_Port);    //读文件指令 -- IP地址还是服务器端的地址不变，端口是由服务器下发的
			IAPVarTypeStruct_Ptr->TftpStart = 0x00;
			break;

	}
}


/*******************************************
**函数名：Internal_TFTP_Task
**参  数：NONE
**作  用：TFTP任务函数
	1、局域网升级
	2、云端升级
	3、日志上报
**返回值：无        
********************************************/
//uint8_t tftp_ip[4] = {192,168,0,7};
void Internal_TFTP_Task(void)
{
	if(IAPVarTypeStruct_Ptr == NULL)  return;   		//未分配空间
	static uint8_t tftp_ack_num = 0;
	#if TFTP_GET_IP
	static uint8_t   tftp_request_flag = 0;   //2022-11-16
	static uint32_t  tftp_request_tick = 0;   //2022-11-16
	#endif
	
	if(IAPSTART == IAPVarTypeStruct_Ptr->IapState)  	//升级开始
	{
		/*判断升级类型*/
		if( (IAPVarTypeStruct_Ptr->IapType == IAPTFTPWRITE) || (IAPVarTypeStruct_Ptr->IapType == IAPTFTPREAD) )
		{
			switch(Udp_IAP_sta)
			{
				case STA_INIT:
					if((CH57xNET_GetPHYStatus() < 2) || (server_info.init_flag == 0x00))  return;       //网络未初始化完成，返回
					
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"开始创建TFTP服务套接字...");
					UDPSocketParamInit2(&net_info.SocketId[1], 69, UDPSocket2_AppCallBack);    		//创建套接字,TFTP服务
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"开始创建TFTP文件传输套接字...");
					UDPSocketParamInit2(&net_info.SocketId[2], 65535, UDPSocket3_AppCallBack);    	//创建套接字,TFTP文件传输
					Udp_Internal_tick = SysTick_10ms;
					Udp_IAP_sta = STA_INIT_WAIT;
					
					IAPVarTypeStruct_Ptr->processing_tick = SysTick_1ms;
					break;
				
				case STA_INIT_WAIT:                          //等待初始化完成，创建套接字需延时一段时间才能正常收发数据
					if(SysTick_10ms - Udp_Internal_tick > 5)
					{
						Udp_IAP_sta = STA_INIT_IDLE;
					}
					break;
				case STA_INIT_IDLE:                        //
					TFTP_CMD_ACK(server_info.goal_ip, server_info.goal_port);    //回复TFTP命令
					break;
			}
			
			if( SysTick_1ms - IAPVarTypeStruct_Ptr->processing_tick > TFTP_IAP_Timeout)		//升级超时，释放套接字
			{
				Cloud_IAP_Plan_SendPack(tftp_args,IAPVarTypeStruct_Ptr,IAPPlan_State_IAPTimeout);		//升级超时
				
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP 升级超时，释放套接字");
				
				CH57xNET_SocketClose(net_info.SocketId[1], TCP_CLOSE_NORMAL);                     	//就关闭65535-文件传输套接字
				CH57xNET_SocketClose(net_info.SocketId[2], TCP_CLOSE_NORMAL);  	//关闭69-TFTP服务套接字
				Udp_IAP_sta = STA_INIT;        									//将升级服务状态置为需要初始化
				IAPVarTypeStruct_Ptr->IapErrFlag = 0;

				if(IAPVarTypeStruct_Ptr != NULL)	free(IAPVarTypeStruct_Ptr);
				IAPVarTypeStruct_Ptr = NULL;
				
				if(tftp_args != NULL)	free(tftp_args);
				tftp_args = NULL;
			}
			
		}else if(IAPVarTypeStruct_Ptr->IapType == IAPTFTPLOG)
		{
			switch(TFTP_LOG_sta)
			{
				case STA_INIT:
					if((CH57xNET_GetPHYStatus() < 2) || (server_info.init_flag == 0x00))  return;       //网络未初始化完成，返回
					/*TFTP文件主动传输 - 一个套接字搞定*/
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"开始创建TFTP服务套接字...");
					UDPSocketParamInit2(&net_info.SocketId[1], TFTP_LOG_Local_Port, TFTP_LOG_CallBack);    		//创建套接字,TFTP服务
					Udp_Internal_tick = SysTick_10ms;
					TFTP_LOG_sta = STA_INIT_WAIT;
					tftp_ack_num = 0x00;
					break;
				
				case STA_INIT_WAIT:                          //等待初始化完成，创建套接字需延时一段时间才能正常收发数据
					if(SysTick_10ms - Udp_Internal_tick > 5)
					{
						TFTP_LOG_sta = STA_INIT_CONNECT;
					}
					break;
				case STA_INIT_CONNECT:	//创建TFTP数据端口连接 65500~65509
					if(SysTick_10ms - Udp_Internal_tick > 1)
					{
						Udp_Internal_tick = SysTick_10ms;
						if(tftp_ack_num >= 10)
						{
							tftp_ack_num = 0;
							TFTP_LOG_sta = STA_LOG;
						}else {
							uint32_t temp_prot = TFTP_LOG_Local_Port + tftp_ack_num;
							
							TFTP_LOG_Write_Connect(server_info.tftp_ip,temp_prot);
							
							tftp_ack_num++;
						}
					}
					break;
				
				case STA_SEND_WAIT:
					if(SysTick_10ms - Udp_Internal_tick > 500)
					{
						Udp_Internal_tick = SysTick_10ms;
						TFTP_LOG_sta = STA_LOG;
						tftp_ack_num++;
						if(tftp_ack_num >= 0x03)
						{
							#if TFTP_GET_IP
							switch(tftp_request_flag)
							{
								case 0x00:
									Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP Flag:%d\n",tftp_request_flag);
									tftp_ack_num = 0x00;
									tftp_request_flag = 0x01;
									Udp_Internal_QueryTFTPIP_CMD();
									if((SysTick_10ms - tftp_request_tick > 1000) && (server_info.tftpip_gflag == 0x01))
									{
										server_info.tftpip_gflag = 0x00;
										tftp_request_tick = SysTick_10ms;
										TFTP_LOG_sta = STA_LOG;
									}
									break;
								case 0x01:
									Dbg_Println(DBG_BIT_NET_STATUS_bit,"TFTP Flag:%d\n",tftp_request_flag);
									tftp_request_flag = 0x00;
									tftp_ack_num = 0x00;
									TFTP_LOG_sta = STA_END;
									break;
								default:
									break;
							}
							#else
							tftp_ack_num = 0x00;
							TFTP_LOG_sta = STA_END;
							#endif
						}
					}
					break;
					
				
				case STA_LOG:	//发送日志-写命令
					/*写日志 - 第一步：向TFTP服务端口发送写请求 - 套接字1
						同时 - 获取LOG文件大小，同时计算得出块号
						这里没有等待回复应答
					*/
					if(TFTP_LOG_Write_Requests(server_info.tftp_ip,tftp_log.Port) == 0xF0)	
					{
						TFTP_LOG_sta = STA_END;		//日志文件为空
					}else {
						TFTP_LOG_sta = STA_SEND_WAIT;	//等待应答
						Udp_Internal_tick = SysTick_10ms;
						#if TFTP_GET_IP
						tftp_request_tick = SysTick_10ms;
						#endif
					}
					
					break;

				case STA_INIT_IDLE:           
					/*等待超时*/
					if(SysTick_1ms - tftp_args->last_time > 10000 )
					{
						tftp_args->last_time = SysTick_1ms;
						tftp_args->retry_num++;
						if(tftp_args->retry_num > 12)
						{
							TFTP_LOG_sta = STA_END;
						}else {
							TFTP_LOG_sta = STA_SEND_RETRY;
						}
					}
					
					break;
				case STA_SEND_LOG:
					/*开始发送LOG数据*/
					IAP_tftp_write_LOG_Data(server_info.tftp_ip, server_info.goal_port);
					if(tftp_args == NULL)	{
						TFTP_LOG_sta = STA_END;
						return ;
					}
					tftp_args->last_time = SysTick_1ms;
					TFTP_LOG_sta = STA_INIT_IDLE;
					break;
				case STA_SEND_RETRY:
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"重新发送一次数据...");
					IAP_tftp_Retry_write_LOG_Data(server_info.tftp_ip, server_info.goal_port);
					tftp_args->last_time = SysTick_1ms;
					TFTP_LOG_sta = STA_INIT_IDLE;
					break;
				case STA_END:
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"关闭套接字，释放申请空间...");
					/*关闭套接字，释放申请空间*/
					CH57xNET_SocketClose(net_info.SocketId[1],0x00);
					
					IAPVarTypeStruct_Ptr->IapState = IAPFINISH;
					if(IAPVarTypeStruct_Ptr != NULL)	free(IAPVarTypeStruct_Ptr);
					IAPVarTypeStruct_Ptr = NULL;
						
					if(tftp_args != NULL)	free(tftp_args);
					tftp_args = NULL;
				
					TFTP_LOG_sta = STA_INIT;
					#if TFTP_GET_IP
					tftp_request_flag = 0x00;
					#endif
					break;
				default:
					TFTP_LOG_sta = STA_INIT;
					break;
			}
		}
	}
}

/*取断电状态变化 查询函数
	任意一个状态变化，便主动上报

2026-01-20 修改点：
	1、任意一个状态变化时，记录一下当前RCU主机时间戳；
	2、在判断取电服务状态是否有变化时，也判断一下时间戳是否处于上报时间范围内，如果不处于上报时间范围内，便不进行数据上报
	3、如果当前取电变化数据正在进行数据上报，这时产生取电变化了，应该将动作重新组包，发生次数清零，重新数据发送。

*/
uint8_t UDP_ActSend_PowerChange_Scan_State(void)
{
	uint8_t temp_state = 0,last_temp_state = 0,temp_flag = 0,last_temp_flag = 0;
	uint32_t temp_tick = 0;
	
	/*判断取电服务状态是否有变化*/
	temp_flag = SRAM_Read_Byte(SRAM_UDP_ELEReport_Action);
	last_temp_flag = temp_flag;
	
	temp_tick = SRAM_Read_DW(SRAM_UDP_ELEReport_EleState_Tick);
	if(SysTick_1ms - temp_tick <= 4000)
	{
		temp_tick = SysTick_1ms;
		
		SRAM_Write_DW(temp_tick,SRAM_UDP_ELEReport_EleState_Tick);
		temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_EleState);
		last_temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_EleState_Last);
		if( temp_state != last_temp_state )
		{
			SRAM_Write_Byte(temp_state,SRAM_UDP_ELEReport_EleState_Last);
			temp_flag |= 0x01;
		}
	}
	
	temp_tick = SRAM_Read_DW(SRAM_UDP_ELEReport_CardState_Tick);
	if(SysTick_1ms - temp_tick <= 4000)
	{
		temp_tick = SysTick_1ms;
		
		SRAM_Write_DW(temp_tick,SRAM_UDP_ELEReport_CardState_Tick);
		temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_CardState);
		last_temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_CardState_Last);
		if(temp_state != last_temp_state)
		{
			SRAM_Write_Byte(temp_state,SRAM_UDP_ELEReport_CardState_Last);
			temp_flag |= 0x02;
		}
	}
	
	temp_tick = SRAM_Read_DW(SRAM_UDP_ELEReport_CardType_Tick);
	if(SysTick_1ms - temp_tick <= 4000)
	{
		temp_tick = SysTick_1ms;
		
		SRAM_Write_DW(temp_tick,SRAM_UDP_ELEReport_CardType_Tick);
		temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_CardType);
		last_temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_CardType_Last);
		if(temp_state != last_temp_state)
		{
			SRAM_Write_Byte(temp_state,SRAM_UDP_ELEReport_CardType_Last);
			temp_flag |= 0x04;
		}
		
	}
	

	temp_tick = SRAM_Read_DW(SRAM_UDP_ELEReport_VirtualCard_Tick);
	if(SysTick_1ms - temp_tick <= 4000)
	{
		temp_tick = SysTick_1ms;
		
		SRAM_Write_DW(temp_tick,SRAM_UDP_ELEReport_VirtualCard_Tick);
		temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_VirtualCard);
		last_temp_state = SRAM_Read_Byte(SRAM_UDP_ELEReport_VirtualCard_Last);
		if(temp_state != last_temp_state)
		{
			SRAM_Write_Byte(temp_state,SRAM_UDP_ELEReport_VirtualCard_Last);
			temp_flag |= 0x08;
		}
	}
	
	
	if(temp_flag != last_temp_flag)
	{
		SRAM_Write_Byte(temp_flag,SRAM_UDP_ELEReport_Action);
		
		if( ((server_info.active_cmd_flag & UDP_ActSend_PowerChange_Flag) != 0x00) && (server_info.udp_send_flag == UDP_ActSend_PowerChange_Flag) )
		{
			/*当前正在发送 - 次数清零，重新开始发生*/

			if( (server_info.udp_sta == 0x03) || (server_info.udp_sta == 0x04) )
			{
				//当前正在发送 - 次数清零，重新开始发生

				server_info.udp_sta = 0x02;
			}
			
		}else {
			server_info.active_cmd_flag |= UDP_ActSend_PowerChange_Flag;
		}
		
		
		
		
		/* */
	}
	
	return temp_flag;
}

/*******************************************
* 函数名：BLV_UDP_Comm_Task
* 参  数：
* 作  用：局域网相关的任务处理    
* 返回值：无        
* 调用方式：主循环中调用
********************************************/
void BLV_UDP_Comm_Task(void)
{
	static uint32_t udp_state_tick = 0;
	uint32_t temp_val = 0;
	
	/*函数主要任务 - 主动发送数据*/
	if( SysTick_1ms - udp_state_tick >= 100 )
	{
		udp_state_tick = SysTick_1ms;
		
		if(server_info.init_flag == 0x00) return ;		//DNS解析域名失败直接退出
		
		/*并且不再TFTP任务中*/
		if(IAPVarTypeStruct_Ptr != NULL)
		{
			if(IAPSTART == IAPVarTypeStruct_Ptr->IapState)	
			{
				Dbg_Println(DBG_BIT_NET_STATUS_bit,"RoomState_Cmd暂停,IAP任务中..");
				return;		
			}
		}
		
		server_info.udp_scan_cnt++;
		if(server_info.udp_scan_cnt >= 9)
		{
			server_info.udp_scan_cnt = 0x00;
			
			server_info.udp_timesync_cnt++;
			server_info.udp_periodic_cnt++;
			
			//判断时间同步 - 有没有到时间
			if(server_info.udp_timesync_cnt >= 7200){
				server_info.udp_timesync_cnt = 0x00;
				server_info.active_cmd_flag |= UDP_ActSend_TimeSync_Flag;
			}
			//判断定期上报 - 有没有到时间
			if(server_info.udp_periodic_cnt >= server_info.udp_periodic_time){
				server_info.udp_periodic_cnt = 0x00;
				server_info.active_cmd_flag |= UDP_ActSend_Periodic_Flag;
			}
			
			//判断RCU启用原因标志位成不成立
			if(server_info.rcu_reboot_flag == 0x01){
				server_info.rcu_reboot_flag = 0x00;
				
				server_info.active_cmd_flag |= UDP_ActSend_Reboot_Flag;			//上报RCU启动原因
			}
			
			UDP_ActSend_PowerChange_Scan_State();		//扫描取电主动上报命令
			
			Udp_Scan_Roomstate();		//扫描房间设备状态
		}
		
		switch(server_info.udp_sta)
		{
			case 0x01:		//注册
				if(server_info.register_flag == 0x01)
                {
                    if(SysTick_1s - server_info.register_tick > USER_NET_Register_Timeout)	//每30S 发送一次注册命令
                    {
                        Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP注册数据发送超时 %d",server_info.register_num);
                        server_info.register_tick = SysTick_1s;
                        server_info.register_num++;
                        server_info.register_flag = 0x00;
                        
                        if(server_info.register_num >= USER_NET_Register_Times)		server_info.init_flag = 0x00;
                    }
                    
                    return ;
                }
				
                Dbg_Println(DBG_BIT_NET_STATUS_bit,"UDP注册数据发送");  
                UDP_Search_Ack();  			//如果不在服务器就一直注册
				server_info.udp_idle_tick = SysTick_1ms;
                server_info.register_flag = 0x01;
                server_info.register_tick = SysTick_1s;
				break;
			case 0x02:		//判断数据包是否需要发送
				
				/*UDP 判断是否达到空闲状态*/
				if(SysTick_1ms - server_info.udp_idle_tick >= 30000)
				{
					server_info.udp_idle_tick = SysTick_1ms;
					
					//发送心跳包
					server_info.active_cmd_flag |= UDP_ActSend_Heart_Flag;
				}
				
				/*UDP 网络离线判断*/
				if(SysTick_1ms - server_info.udp_online_tick >= server_info.udp_online_time)
				{
					server_info.udp_online_tick = SysTick_1ms;
					
					server_info.init_flag = 0x00;				//UDP网络离线
					LOG_SYS_Server_Comm_State_Record(RCU_NO_SERVER);
					return ;
				}
				
				for(uint8_t i=0;i<7;i++)
				{
					if( ( server_info.active_cmd_flag & (0x01 << i) ) != 0x00 )
					{
						server_info.udp_send_flag = 0x01 << i;
						server_info.udp_sta = 0x03;
						
						server_info.udp_retry_cnt = 0x00;
						server_info.udp_retry_time = 2000;
						break;
					}
				}
				
				break;
			case 0x03:		//数据包发送
				switch(server_info.udp_send_flag)
				{
					case 0x01:		//取断电上报 - 优先级最高
						Udp_Internal_Power_Change_Report_CMD();
						
						server_info.udp_retry_num = 0x02;			//一共发送3次
						server_info.udp_retry_tick = SysTick_1ms;
						server_info.udp_idle_tick = SysTick_1ms;
						server_info.udp_sta = 0x04;					//进入发送等待
						break;
					case 0x02:		//设备状态上报 - 
						Udp_Internal_RoomState();
					
						server_info.udp_retry_num = 0x02;			//一共发送3次
						server_info.udp_retry_tick = SysTick_1ms;
						server_info.udp_idle_tick = SysTick_1ms;
						server_info.udp_sta = 0x04;					//进入发送等待
						break;
					case 0x04:		//定期上报 - 只发送一次
						Udp_Internal_Periodic_Report_PackSend();
						
						server_info.udp_idle_tick = SysTick_1ms;
						server_info.udp_send_flag = 0x00;
						server_info.active_cmd_flag &= ~UDP_ActSend_Periodic_Flag;
						server_info.udp_sta = 0x02;
						break;
					case 0x08:		//上报RCU重启原因 - 
						Udp_Internal_Reboot_Reason_Report_CMD();
						
						server_info.udp_retry_num = 0x02;			//一共发送3次
						server_info.udp_retry_tick = SysTick_1ms;
						server_info.udp_idle_tick = SysTick_1ms;
						server_info.udp_sta = 0x04;					//进入发送等待
						break;
					case 0x10:		//获取房态 - 
						Udp_Internal_GetRoomRent_CMD();
						
						server_info.udp_retry_num = 0x02;			//一共发送3次
						server_info.udp_retry_tick = SysTick_1ms;
						server_info.udp_idle_tick = SysTick_1ms;
						server_info.udp_sta = 0x04;					//进入发送等待
						break;
					case 0x20:		//时间同步 - 
						Udp_Internal_GetTime_CMD();
						
						server_info.udp_retry_num = 0x02;			//一共发送3次
						server_info.udp_retry_tick = SysTick_1ms;
						server_info.udp_idle_tick = SysTick_1ms;
						server_info.udp_sta = 0x04;					//进入发送等待
						break;
					case 0x40:		//心跳包 - 空闲30S 发送一次
						UDP_Heart_Send();
						
						server_info.udp_idle_tick = SysTick_1ms;
						server_info.udp_send_flag = 0x00;
						server_info.active_cmd_flag &= ~UDP_ActSend_Heart_Flag;
						server_info.udp_sta = 0x02;		
						break;
					default:
						server_info.udp_sta = 0x02;		
						break;
				}
				return ;		//发送数据完毕直接退出
				
			case 0x04:		//等待数据ACK
				
				if(server_info.udp_send_flag == 0x00)		{
					server_info.udp_sta = 0x02;				//接收到回复数据了，结束发送
					break;
				}
				
				if( server_info.udp_retry_cnt <= server_info.udp_retry_num )
				{
					if( SysTick_1ms - server_info.udp_retry_tick >= server_info.udp_retry_time)
					{
						server_info.udp_retry_tick = SysTick_1ms;
						//发送超时
						
						server_info.udp_retry_cnt++;
						if(server_info.udp_retry_cnt > server_info.udp_retry_num)
						{
							//数据重发已达上限，清楚发送标志位
							
							if(server_info.udp_send_flag == 0x02)		//如果是设备状态发送失败，清楚发送缓冲区内容
							{
								temp_val = SRAM_Read_DW(SRAM_UDP_SendData_Tempaddr);
								SRAM_Write_DW(temp_val, SRAM_UDP_SendData_Readaddr);				//读地址复位
								Dbg_Println(DBG_BIT_NET_STATUS_bit,"上报设备状态失败 读:%8X",temp_val);
								
								temp_val = SRAM_Read_DW(SRAM_DEVICE_ONLINE_STATE_TEMP_ADDR);	//读临时保存的故障读取地址
								SRAM_Write_DW(temp_val, SRAM_DEVICE_ONLINE_STATE_READ_ADDR);	//故障读地址重新赋值
								Dbg_Println(DBG_BIT_NET_STATUS_bit,"上报设备故障失败 读:%8X",temp_val);
							}
							
							server_info.active_cmd_flag &= ~server_info.udp_send_flag;
							server_info.udp_sta = 0x02;		//结束发送
						}else {
							server_info.udp_sta = 0x03;		//数据发送
							server_info.udp_retry_time += 2000;
						}
						
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"udp_retry:%02x - %d - %d",server_info.udp_send_flag,server_info.udp_retry_cnt,server_info.udp_retry_time);
					}
				}else {
					//数据重发已达上限，清楚发送标志位
					
					server_info.active_cmd_flag &= ~server_info.udp_send_flag;
					server_info.udp_sta = 0x02;				//结束发送
				}
				break;
			default:
				server_info.udp_sta = 0x02;
				break;
		}
		
	}
	
	/*函数附带任务 - 搜索命令的被动回复 增加随机延时 随机延时采用MAC地址最后一位 * 2ms */
	if(server_info.search_ack_flag == 0x01)
	{
		uint32_t temp_tick = 0;
		
		temp_tick = MACAddr[5];
		temp_tick = temp_tick * 2;
		
		if( SysTick_1ms - server_info.search_ack_tick >= temp_tick )
		{
			server_info.search_ack_tick = SysTick_1ms;
			server_info.search_ack_flag = 0x00;
			
			Udp_Internal_Read_MCU_System_SendAck(server_info.udp_ip,server_info.local_port,server_info.ack_frame);
		}
	}
	
	
}

/*******************************************
**函数名：Udp_Internal_Task
**参  数：data：接受到的数据   len：长度   ip：网络地址  port：端口
**作  用：局域网相关的任务处理    
**返回值：无        
*调用方式：主循环中调用
**局域网服务套接字常开，TFTP的服务和文件传输套接字在升级完后会关闭
********************************************/
void Udp_Internal_Task(void)
{
	uint8_t rev = 0;
	switch(server_info.Udp_Internal_sta)
	{
		case STA_INIT:
			if(CH57xNET_GetPHYStatus() < 2)  return;       //网络未初始化完成，返回
			Dbg_Println(DBG_BIT_NET_STATUS_bit," 网络初始化完毕 ， 开始创建套接字...");
			
			server_info.init_flag = 1;					//网络初始化完成
		#if MQTT_EN
			LOG_SYS_NET_Argc_Record(net_info.local_ip,MACAddr,server_info.dis_ip,server_info.tftp_ip,mqtt_info.des_ip);		//记录网络初始化信息
		#else
		{
			uint8_t temp_buff_mqtt[4] = {0};
			LOG_SYS_NET_Argc_Record(net_info.local_ip,MACAddr,server_info.dis_ip,server_info.tftp_ip,temp_buff_mqtt);
		}
		#endif
			CH57xNET_SocketClose(net_info.SocketId[0],0x00);
		
			UDPSocketParamInit2(&net_info.SocketId[0], 3341, UDPSocket1_AppCallBack);    //创建套接字,局域网等待接收升级或配置发布等命令
		
			Udp_Internal_tick = SysTick_10ms;
			server_info.Udp_Internal_sta = STA_INIT_WAIT;
			Udp_IAP_sta = STA_INIT;
			SRAM_Write_Byte(0x00,SRAM_IAP_UPGRADE_Reply_NUM_ADDRESS);
			break;
		case STA_INIT_WAIT:                          //等待初始化完成，创建套接字需延时一段时间才能正常收发数据
			if(SysTick_10ms - Udp_Internal_tick >= 10)
			{
				Udp_Internal_tick = SysTick_10ms;

				if((SRAM_Read_Byte(SRAM_IAP_NET_UPGRADE_Flag_ADDRESS) == IAP_STATE_COMPLETE))		
				{
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"回复-网络升级成功..");
					rev = Udp_Internal_ReplyIAP();		//判断当前是网络升级
					if(rev == CH57xNET_ERR_SUCCESS)
					{
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"回复成功！");
						SRAM_Write_Byte(0xFF,SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);	//清空网络升级标志位
						server_info.Udp_Internal_sta = STA_INIT_IDLE;
					}else {
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"回复失败！");
						rev = SRAM_Read_Byte(SRAM_IAP_UPGRADE_Reply_NUM_ADDRESS);
						if(rev >= 5)	server_info.Udp_Internal_sta = STA_INIT_IDLE;;
						rev++;
						SRAM_Write_Byte(rev,SRAM_IAP_UPGRADE_Reply_NUM_ADDRESS);
					}
				}
				else if((SRAM_Read_Byte(SRAM_IAP_NET_UPGRADE_Flag_ADDRESS) == CLOUD_IAP_TFTP_STATE_COMPLETE))	
				{
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"回复-云端网络升级成功..");
					rev = Cloud_Internal_ReplyIAP();		//判断当前是云端网络升级
					if(rev == CH57xNET_ERR_SUCCESS)
					{
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"回复成功！");
						SRAM_Write_Byte(0xFF,SRAM_IAP_NET_UPGRADE_Flag_ADDRESS);	//清空网络升级标志位
						server_info.Udp_Internal_sta = STA_INIT_IDLE;
					}else {
						Dbg_Println(DBG_BIT_NET_STATUS_bit,"回复失败！");
						rev = SRAM_Read_Byte(SRAM_IAP_UPGRADE_Reply_NUM_ADDRESS);
						if(rev >= 5)	server_info.Udp_Internal_sta = STA_INIT_IDLE;
						rev++;
						SRAM_Write_Byte(rev,SRAM_IAP_UPGRADE_Reply_NUM_ADDRESS);
					}
				}
				else 
				{
					server_info.Udp_Internal_sta = STA_INIT_IDLE;
				}
				
			}
			break;
		case STA_INIT_IDLE:
			//Dbg_Println(DBG_BIT_NET_STATUS_bit,"\n");
			//UDP_Search_Ack();  			//向云端注册
			server_info.Udp_Internal_sta = STA_SEND_RETRY;
			break;
		case STA_SEND_RETRY:	
			
			Internal_TFTP_Task();                  		//TFTP任务
		
			BLV_UDP_Comm_Task();
		
			Udp_Internal_Dev_Control_Processing();		//服务器下发控制数据处理
		
			break;
	}
}




