/******************************************************************************
版权所有：	
文件名称：	net_104.c
文件版本：	01.01
创建作者:	   sunxi
创建日期：	2012-11-07
功能说明：	网络104接口
其它说明：
修改记录：
*/
#ifdef CPU_FUXI
/*------------------------------- 头文件 --------------------------------------
*/
#include "head.h"
#include <pthread.h>
#include <errno.h>
#include <sys/prctl.h>

/*------------------------------- 宏定义 --------------------------------------
*/
#define NET_104_BUF_SIZE   16384


/*------------------------------ 类型结构 -------------------------------------
*/


/*------------------------------ 全局变量 -------------------------------------
*/
// static struct task_struct * g_ts_104[IEC104_TOTAL_SOCKETS];
static pthread_t g_ts_104[IEC104_TOTAL_SOCKETS] = {0x00};
static SOCKET g_104_client[IEC104_TOTAL_SOCKETS];

static unsigned char g_net_104_buf_frame[IEC104_TOTAL_SOCKETS][NET_RECV_MAX];  // 以太网接收缓冲区
static unsigned char g_net_104_buf[IEC104_TOTAL_SOCKETS][NET_104_BUF_SIZE];  // 以太网接收缓冲区
static struct rt_fifo	g_net_104_fifo[IEC104_TOTAL_SOCKETS];

static volatile int g_net_reinit[CFG_ETH_MAX_LOGIC]={NET_SOCKET_INIT};//网络重新初始化标志.0表示不用重新初始化，1表示需要重新初始化
// static struct semaphore net_r_lock[CFG_ETH_MAX_LOGIC];		//接收锁
// static struct semaphore net_s_lock[CFG_ETH_MAX_LOGIC];		//发送锁
static pthread_mutex_t net_r_lock[CFG_ETH_MAX_LOGIC];		//接收锁
static pthread_mutex_t net_s_lock[CFG_ETH_MAX_LOGIC];		//发送锁

static int g_net_104_close_flag[CFG_ETH_MAX_LOGIC];
static int g_net_104_exit_flag[CFG_ETH_MAX_LOGIC];

// static struct completion g_exit_completion_net_104[CFG_ETH_MAX_LOGIC];

extern u32	g_ip_net_maintain;	// 104维护工具调试客户端地址

/*------------------------------ 函数声明 -------------------------------------
*/
int _net_104_thread(IEC104_DEF *pt104);


//设置socket关闭标志并等待socket关闭完成
void net_104_set_sock_closing(int no)
{
    //if(no >=  g_net_num) return;

    g_net_reinit[no] = NET_SOCKET_CLOSING; //置关闭标志

    if(!tRunPara.b104Client)
    {   
	    int count=0;
        //等待关闭完成
        while(g_net_reinit[no] != NET_SOCKET_CLOSED)
        {
            msleep(20);
            if(++count>150)
            {
             	rt_printf("104 client socket close fail!!!\r\n");
             	return;
            }
        }
    }

}

//设置socket重新创建标志
void net_104_set_sock_initflag(int no)
{
//	if(no >=  g_net_num) return;
	
	if(g_net_reinit[no] == NET_SOCKET_CLOSED)
	{
		g_net_reinit[no] = NET_SOCKET_REINIT;	
	}
	
}

/**************************************************************************
函数名称：Net_Init
函数版本：1.00 
作者：	
创建日期：2009.1.8    
函数功能说明：以太网初始化
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/
void Net_Init(void)
{
	unsigned char mac[6];
	unsigned char ip[4];
	unsigned char mask[4];
	unsigned char gw[4];
	unsigned char routenet[4];
	unsigned char routenetmask[4];
	unsigned char routegate[4]; 
	//char * acteth;
	int i,j;
	//char tmp[16];
	int ret = 0;
	int gateflag = 0;

	if(tRunPara.w104K == 0)
	{
		if(pRunSet->bTT_SoeResumeComm || pRunSet->bTT_SoeResumePower)
		{
			rt_printf("定值参数错误：SOE通讯续传、SOE上电续传时参数104 K值不能为0.\r\n");
			rt_err_set(ERR_CODE_INIT_SOFTWARE,0);
		}
	}

#if 0
	int debug_port;
	acteth = env_get_info(ENV_ETHACT);
	if(acteth != NULL)
	{
		if(strcmp(acteth,"eth0") == 0)
		{
			debug_port = 0;
		}
		else if(strcmp(acteth,"eth1") == 0)
		{
			debug_port = 1;
		}
		else if(strcmp(acteth,"eth2") == 0)
		{
			debug_port = 2;
		}
		else
		{
			debug_port = 2;
		}

	}
	else
	{
		debug_port = 2;

	}
#endif

	//for(i=0;i<g_net_num;i++)
	for(i=0;i<CFG_ETH_MAX_LOGIC;i++)
	{
		//没有改变参数，不用初始化
		if(!tRunPara.tNetPara[i].bInit)
		{
			//104配置参数有修改,需关闭socket重新初始化
			if(tRunPara.sock_104_flag)
			{
				net_104_set_sock_initflag(i);	
			}		
		
			continue;
		}
		gateflag = 1;
		tRunPara.tNetPara[i].bInit=false;

		// 设置接口MAC地址
		//if(rt_if_sz2mac(env_get_info(ENV_NET1MAC+i),mac)< 0)
		mac[0] = 'H';
		mac[1] = 'G';
		mac[2] = (BYTE)((tRunPara.tNetPara[i].wIp>>24)&0xff);
		mac[3] = (BYTE)((tRunPara.tNetPara[i].wIp>>16)&0xff);
		mac[4] = (BYTE)((tRunPara.tNetPara[i].wIp>>8)&0xff);
		mac[5] = (BYTE)((tRunPara.tNetPara[i].wIp>>0)&0xff);
		
		// 设置IP
		memset(ip,0,sizeof(ip));
		ip[3] = (BYTE)((tRunPara.tNetPara[i].wIp>>0)&0xff);//低 
		ip[2] = (BYTE)((tRunPara.tNetPara[i].wIp>>8)&0xff);
		ip[1] = (BYTE)((tRunPara.tNetPara[i].wIp>>16)&0xff);
		ip[0] = (BYTE)((tRunPara.tNetPara[i].wIp>>24)&0xff);//高 192

		// 设置MASK
		memset(mask,0,sizeof(mask));
		mask[3] =  (BYTE)((tRunPara.tNetPara[i].wMask>>0)&0xff);
		mask[2] =  (BYTE)((tRunPara.tNetPara[i].wMask>>8)&0xff);
		mask[1] = (BYTE)((tRunPara.tNetPara[i].wMask>>16)&0xff);
		mask[0] = (BYTE)((tRunPara.tNetPara[i].wMask>>24)&0xff);

		//检查是否需要关闭虚拟网卡
		if((int)tRunPara.tNetPara[i].old_index > 0)
		{
			rt_if_down2(tRunPara.tNetPara[i].old_ethid, tRunPara.tNetPara[i].old_index);	
		}
		//获取配置相同的ethid有多少个
		ret=get_ethcnt(i, tRunPara.tNetPara[i].ethid);
		
		//没有的话，使用物理的
		if(ret==0)
		{
		
			 // 设置网络参数
			 net_if_set((int)tRunPara.tNetPara[i].ethid,mac,ip, mask);
			 tRunPara.tNetPara[i].index = 0;

			 //rt_printf_time("ret = %d, ethID = %d\r\n",ret,tRunPara.tNetPara[i].ethid);
		}
		else  //有的话使用虚拟的
		{
		 #if (1)
             printf("[%s:%d]\r\n", __func__, __LINE__);
			 net_if_set2((int)tRunPara.tNetPara[i].ethid, ret+1, 0, ip, mask);
		 #else
			 net_if_set2((int)tRunPara.tNetPara[i].ethid, i+1, 0, ip, mask);	
		 #endif
			 
			 tRunPara.tNetPara[i].index = i+1;	
			 
			 //rt_printf_time("Xnet = %d,ip=%x, ethID = %d, ret = %d\r\n",tRunPara.tNetPara[i].index,ip[3],tRunPara.tNetPara[i].ethid,ret);
		}


		 tRunPara.tNetPara[i].old_ethid=  tRunPara.tNetPara[i].ethid;
		 tRunPara.tNetPara[i].old_index=  tRunPara.tNetPara[i].index;
		 

#if 0
		// 如果是调试串口，不初始化
		if(i == debug_port)
		//if(i==(CFG_ETH_MAX_LOGIC-1))
		{
			//设置IP环境变量
			if(tRunPara.tNetPara[i].changed & 0x01)
			{
				sprintf(tmp, "%lu.%lu.%lu.%lu",( tRunPara.tNetPara[i].wIp>>24)&0xff, (tRunPara.tNetPara[i].wIp>>16)&0xff, (tRunPara.tNetPara[i].wIp>>8)&0xff, (tRunPara.tNetPara[i].wIp&0xff));
				env_setenv("ipaddr", tmp); 
			}
			
			//设置Gate环境变量
			if(tRunPara.tNetPara[i].changed & 0x02)
			{
				sprintf(tmp, "%lu.%lu.%lu.%lu", ( tRunPara.tNetPara[i].wGate>>24)&0xff, (tRunPara.tNetPara[i].wGate>>16)&0xff, (tRunPara.tNetPara[i].wGate>>8)&0xff, (tRunPara.tNetPara[i].wGate&0xff));
				if(tRunPara.tNetPara[i].wGate)
					env_setenv("gatewayip", tmp); 
			}		

			//设置Mask环境变量
			if(tRunPara.tNetPara[i].changed & 0x04)
			{
				sprintf(tmp, "%lu.%lu.%lu.%lu", ( tRunPara.tNetPara[i].wMask>>24)&0xff, (tRunPara.tNetPara[i].wMask>>16)&0xff, (tRunPara.tNetPara[i].wMask>>8)&0xff, (tRunPara.tNetPara[i].wMask&0xff));
				env_setenv("netmask", tmp); 
			}	

			//设置ethact环境变量
			if(tRunPara.tNetPara[i].changed & 0x40)
			{
				if(tRunPara.tNetPara[i].ethid >= 2)
				{
					sprintf(tmp, "%s", "eth2");
				}
				else
				{
					sprintf(tmp, "eth%d", (int)tRunPara.tNetPara[i].ethid);
				}

				env_setenv("ethact", tmp);

			}
			//continue;

		
		}
#endif


		//网段
		routenet[0] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>24)&0xff);
		routenet[1] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>16)&0xff);
		routenet[2] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>8)&0xff);
		routenet[3] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>0)&0xff); 

		//网段掩码
		routenetmask[0] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>24)&0xff);
		routenetmask[1] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>16)&0xff);
		routenetmask[2] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>8)&0xff);
		routenetmask[3] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>0)&0xff);

		//网关
		routegate[0] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>24)&0xff);
		routegate[1] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>16)&0xff);
		routegate[2] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>8)&0xff);
		routegate[3] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>0)&0xff);		
		
		net_route_set(routenet, routenetmask, routegate);
		
		//g_net_reinit[i] = 1;//置重新初始化标志 
		net_104_set_sock_initflag(i);
		net_debug_set_sock_initflag();
		net_maintain_set_sock_initflag();
#if 0
		// 得到并打印新的网络参数
	//	net_if_get(i,mac,ip,mask);
		rt_printf("new mac: %02x:%02x:%02x:%02x:%02x:%02x\r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
		rt_printf("new ip:%d.%d.%d.%d\r\n",ip[0],ip[1],ip[2],ip[3]);
		rt_printf("new mask:%d.%d.%d.%d\r\n",mask[0],mask[1],mask[2],mask[3]);
		rt_printf("new gw:%d.%d.%d.%d\r\n",gw[0],gw[1],gw[2],gw[3]);
#endif
	}


	ret = 0;
	//查找是否关闭物理网卡
	for(i=0;i<g_net_num;i++)
	{
		for(j=0;j<CFG_ETH_MAX_LOGIC;j++)
		{
			if(tRunPara.tNetPara[j].ethid == i)
			{
				ret++; //虚拟网卡使用物理网卡计数
			}
		}

		//没有虚拟网卡使用物理网卡
		if(ret==0)
		{
			rt_if_down(i);
		}

		ret = 0;
	}

	
	// 设置网关
	gw[0] =  (BYTE)((tRunPara.tNetPara[0].wGate>>24)&0xff);
	gw[1] =  (BYTE)((tRunPara.tNetPara[0].wGate>>16)&0xff);
	gw[2] =  (BYTE)((tRunPara.tNetPara[0].wGate>>8)&0xff);
	gw[3] =  (BYTE)((tRunPara.tNetPara[0].wGate>>0)&0xff);

	// 如果地址是默认的0.0.0.0，说明用户不需要网关，
	// 不重设网关，使uboot环境变量中的网关有效，方便调试。
	if(gw[0]==0 && gw[1]==0 && gw[2]==0 && gw[3]==0)
	{
		return;
	}

	if(gateflag)
	{
		net_gateway_set(gw);
	}

	//noted by sunxi: 20230105 eth0需要重新设置mac才能成功。
	for(i=0;i<1;i++)
	{
	
		mac[0] = 'H';
		mac[1] = 'G';
		mac[2] = (BYTE)((tRunPara.tNetPara[i].wIp>>24)&0xff);
		mac[3] = (BYTE)((tRunPara.tNetPara[i].wIp>>16)&0xff);
		mac[4] = (BYTE)((tRunPara.tNetPara[i].wIp>>8)&0xff);
		mac[5] = (BYTE)((tRunPara.tNetPara[i].wIp>>0)&0xff);

		rt_if_down(i);
		net_if_set((int)tRunPara.tNetPara[i].ethid,mac,NULL, NULL);
		rt_if_up(i);

	}


	
	return;
}

	
/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/
int net_104_init(void)
{

	int net;
	char buf[32];
//	struct sched_param sp;
//	pid_t pid;
	int ret;
	pthread_attr_t attr;

	IEC104_Init();

	for(net=0; net<CFG_ETH_MAX_LOGIC; net++)
	//for(net=0; net<1; net++)
	{
		g_104_client[net] = RT_SOCKET_ERR;
		
		// init_completion(&g_exit_completion_net_104[net]);
		g_net_reinit[net] = 0; //初始化标志
		// init_MUTEX(&net_r_lock[net]);//初始化接收锁
		// init_MUTEX(&net_s_lock[net]);//初始化发送锁
		pthread_mutex_init(&net_r_lock[net], NULL);
		pthread_mutex_init(&net_s_lock[net], NULL);
		// 如果接口不正常，不初始化
#if 0
		if(tRunPara.tNetPara[net].index == 0)
		{
			if(rt_if_ip_get(tRunPara.tNetPara[net].ethid, buf)!=0) 
			{
				continue;
			}
				
		}
		else
		{
			if(rt_if_ip_get2(tRunPara.tNetPara[net].ethid, tRunPara.tNetPara[net].index, buf)!=0)
			{
				continue;
			}

		}
		

		// 运行应用104线程
		sprintf(buf,"net_104_%d",net);
		pid = kernel_thread((int (*)(void *))_net_104_thread,&g_t104[net],CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
		g_ts_104[net] = find_task_by_vpid(pid);
		if(IS_ERR(g_ts_104[net]))
		{
			rt_printf("ts=%p\r\n",g_ts_104[net]);
			g_ts_104[net] = NULL;
			return -1;
		}

		// 设置调度策略和优先级
		sp.sched_priority = 8;
		sched_setscheduler(g_ts_104[net],SCHED_FIFO,&sp);
		// 设置进程名字
		set_task_comm(g_ts_104[net], buf);
#endif
		//rt_printf("----------net = %d\r\n", net);

		// 运行应用104线程
		sprintf(buf,"net_104_%d",net);

		// 设置调度策略和优先级
	  	pthread_attr_init(&attr);
		pthread_attr_setschedpolicy(&attr, SCHED_FIFO);  //调度
		struct sched_param s_parm;
		//s_parm.sched_priority = sched_get_priority_max(SCHED_FIFO);
		s_parm.sched_priority = 8;
		pthread_attr_setschedparam(&attr, &s_parm); 	//优先级

		//attr.__schedpolicy = SCHED_FIFO;
		//attr.__schedparam.sched_priority = 8;
		
		ret = pthread_create(&g_ts_104[net], &attr, (void *)_net_104_thread, &g_t104[net]); 
		if(ret != 0) {
			printf("can not create thread _net_104_thread(net=%d): %d\r\n",net,errno);
			return -1;
		}		
		
	}

	return 0;
}


int net_104_exit(void)
{
	int net;
	 
	for(net=0; net<CFG_ETH_MAX_LOGIC; net++)
	{
		if(g_ts_104[net])
		{
			//kthread_stop(g_ts_104[net]);
			g_net_104_exit_flag[net] = 1;
			// wait_for_completion(&g_exit_completion_net_104[net]);
			pthread_join(g_ts_104[net], NULL);
			g_ts_104[net] = 0;
		}
	}

	return 0;
}

int net_104_send_ext(int net,unsigned char *buf,int len)
{
	int ret = 0;
	int ch = net+CFG_UART_NUM_MAX;

	if(g_print_comm_raw && (g_print_port & (1<<ch)))
	{
		char sz[16];
		sprintf(sz,"\r\nTX[%d]:",ch);
		print_mem(sz,buf,len);
		rt_printf("\r\n");
	}

	//down(&net_s_lock[net]);	
	if(g_104_client[net] != RT_SOCKET_ERR)
	{
		ret = rt_send(g_104_client[net],buf,len,0);
	}
	//up(&net_s_lock[net]);

	if(ret < 0)
	{
		rt_printf("net_104_send:ret=%d.\r\n",ret);
	}
	return	ret;
}



int net_104_send(int net,unsigned char *buf,int len)
{
	int ret = 0;
	u8 ti,cot,se;
	u8 *out;
	if(pRunSet->bTT_ESAM)
	{
		iec_GetMsgInfo(buf,len,&ti,&cot,&se,false);
		len =  sec_encrpt_iec(ti,cot,se,buf,len,&out);
		if(len > 0)
		{
			ret=net_104_send_ext(net,out, len);
		}
	}
	else
	{
		ret=net_104_send_ext(net,buf, len);
	}
	return ret;
}

static int net_104_recv(int net, unsigned char *buf,int len)
{
	int ret = 0;

	// down(&net_r_lock[net]);
	pthread_mutex_lock(&net_r_lock[net]);
	if(g_104_client[net] != RT_SOCKET_ERR)
	{	
		ret = rt_recv (g_104_client[net], (void *)buf, NET_RECV_MAX, 0);
	}

	// up(&net_r_lock[net]);
	pthread_mutex_unlock(&net_r_lock[net]);
	return	ret;
}

void net_104_close(int net)
{
	// down(&net_r_lock[net]);
	// down(&net_s_lock[net]);
	pthread_mutex_lock(&net_r_lock[net]);
	pthread_mutex_lock(&net_s_lock[net]);

	if(g_104_client[net] != RT_SOCKET_ERR)
	{
	
		rt_socket_close (g_104_client[net]);
		g_104_client[net] = RT_SOCKET_ERR;	
	}
	
	g_net_104_close_flag[net] = 0;

	// up(&net_s_lock[net]);
	// up(&net_r_lock[net]);
	pthread_mutex_unlock(&net_s_lock[net]);
	pthread_mutex_unlock(&net_r_lock[net]);

}

void net_104_close_flag(int net)
{
	// down(&net_r_lock[net]);
	// down(&net_s_lock[net]);
	pthread_mutex_lock(&net_r_lock[net]);
	pthread_mutex_lock(&net_s_lock[net]);
	
	if(g_104_client[net] != RT_SOCKET_ERR)	
	{
		g_net_104_close_flag[net] = 1;
	}
	
	// up(&net_s_lock[net]);
	// up(&net_r_lock[net]);
	pthread_mutex_unlock(&net_s_lock[net]);
	pthread_mutex_unlock(&net_r_lock[net]);
}

int net_104_is_connect(int net)
{
	if((g_104_client[net] == RT_SOCKET_ERR) || g_net_104_close_flag[net])
	{
		return 0;
	}

	return 1;
}


/*------------------------------ 内部函数 -------------------------------------
内部函数以下划线‘_’开头，不需要检查参数的合法性.
*/
extern int _net_104Client_thread(int net);
int _net_104_thread(IEC104_DEF *pt104)
{
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;

	struct timeval timeout;
	struct linger  ling;

	SOCKET sk_server,sk_tmp ; 

	int net;
	int sin_size;
	int len,ret;
	unsigned char *ip;
	unsigned int ip_server;
	int recv_timeout,recv_timeout_set;
	int link_timeout=0;
	unsigned char buf;
	unsigned char tmpbuf[32];
	u16 w104Port;

/*
	rt_printf("tRunPara.b104Client = %d \r\n",tRunPara.b104Client);
	
	tRunPara.b104Client = 0;

	if(tRunPara.b104Client)  // 104采用客户端
	{
			 
		//net = pt104->cNetIndex;
		net = 1;
		_net_104Client_thread(net);
		//return 0;
	}
*/

#if 1
NET_BEGIN:
	net = pt104->cNetIndex;

	// 服务器端开始建立socket描述符
	sk_server = rt_socket(AF_INET, SOCK_STREAM, 0);
	if (sk_server == RT_SOCKET_ERR)
	{
		RT_PRINTF_POSITION();
		g_ts_104[net] = 0;
		return -1;
	}

	// 服务器端填充sockaddr结构
	memset (&server_addr, 0, sizeof (struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	//rt_if_ip_get(net,(unsigned char *)&ip_server);
	//ret=get_ethcnt(net, tRunPara.tNetPara[net].ethid);


	//IP在物理网卡上
	if( tRunPara.tNetPara[net].index == 0)
	{
		rt_if_ip_get(tRunPara.tNetPara[net].ethid, (unsigned char *)&ip_server);	
		w104Port = tRunPara.w104Port; // 网络1、2使用可变端口，保证级联时不冲突。
	}
	else  //IP在虚拟网卡上
	{
		//从虚拟网卡获取IP地址
		rt_if_ip_get2(tRunPara.tNetPara[net].ethid, tRunPara.tNetPara[net].index, (unsigned char *)&ip_server); 
		w104Port = NET_104_PORT; // 调试网络使用固定的2404端口，保证维护工具可以连接。
	}


	server_addr.sin_addr.s_addr = htonl (ip_server);
	server_addr.sin_port = htons (w104Port);

	//printf("-------Server ip:%s\n",inet_ntoa(server_addr.sin_addr));

	// 捆绑sockfd描述符
	ret = rt_bind (sk_server, (struct sockaddr *)(&server_addr), sizeof (struct sockaddr));
	if (ret < 0)
	{
		// RT_PRINTF_POSITION();
		rt_socket_close (sk_server);
		g_ts_104[net] = 0;
		
		return -2;
	}

	// 监听sockfd描述符
	ret = rt_listen (sk_server, 1);
	if (ret < 0)
	{
		// RT_PRINTF_POSITION();
		rt_socket_close (sk_server);
		g_ts_104[net] = 0;
		
		return -3;
	}
	// 设置接收超时
	timeout.tv_sec	= 0;
	timeout.tv_usec = 100000;
	rt_setsockopt(sk_server,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout ,sizeof(struct timeval));
	
	// 设置关闭延时
	ling.l_onoff = 1;
	ling.l_linger = 0;
	rt_setsockopt(sk_server,SOL_SOCKET,SO_LINGER,(char *)&ling ,sizeof(struct linger));
	ip = (unsigned char *)&ip_server;
	//rt_printf("应用104线程已启动(IP:%d.%d.%d.%d,PORT:%d)。\r\n",ip[0],ip[1],ip[2],ip[3],NET_104_PORT);
	#ifdef CPU_FUXI
	sprintf(tmpbuf,"net_104_%d",net);
	prctl(PR_SET_NAME, tmpbuf);
	#endif
	while(1)
	{
		// 服务器阻塞，直到客户程序建立连接
		sin_size = sizeof (struct sockaddr_in);
		sk_tmp = rt_accept (sk_server, (struct sockaddr*)(&client_addr), &sin_size);
		// 检查是否退出
		if(g_net_104_exit_flag[net])
		{
			// 关闭客户端
			net_104_close(net);
			// 关闭服务器
			rt_socket_close (sk_server);
			// complete_and_exit(&g_exit_completion_net_104[net], 0);
			return 0;
		}
		//是否重新初始化
		if(g_net_reinit[net] == NET_SOCKET_CLOSING)
		{
			// 关闭客户端
			net_104_close(net);
			// 关闭服务器
			rt_socket_close (sk_server);
			//置已经关闭标志
			g_net_reinit[net] = NET_SOCKET_CLOSED;
			//等待IP修改完成
			while(g_net_reinit[net] != NET_SOCKET_REINIT)
			{
				msleep(100);	
			}
			//置为初始化
			g_net_reinit[net] = NET_SOCKET_INIT;
			goto NET_BEGIN; 	
		}
		//注意，用指针类型的socket接口，失败是返回NULL
		//而整数类型的socket接口,失败返回的是负数
		//#ifdef RT_SOCKET_FD
	#if 1
		if (sk_tmp < 0)
		{
			msleep(100);	
			// 超时.
			
			continue;
		}
	#else
		if (sk_tmp == RT_SOCKET_ACCEPT_RST) 
		{
			msleep(100);	
			// 超时
			continue;			
		}
	#endif
		g_104_client[net] = sk_tmp;
		

		ip = (unsigned char *)&client_addr.sin_addr.s_addr;
		rt_printf("104 client[net=%d,s=%d] connect(ip=%d.%d.%d.%d)!\r\n", net ,sk_tmp,ip[0],ip[1],ip[2],ip[3]);

		
#if 0		
		// 检查是否主站IP
		if(tRunPara.ip104Master1 || tRunPara.ip104Master2 || tRunPara.ip104Master3 || tRunPara.ip104Master4)
		{
			u32 network0,network1;
			network0 = client_addr.sin_addr.s_addr & tRunPara.tNetPara[CFG_ETH_MAX_LOGIC-1].wMask;
			network1 = tRunPara.tNetPara[CFG_ETH_MAX_LOGIC-1].wIp & tRunPara.tNetPara[CFG_ETH_MAX_LOGIC-1].wMask;
			
			if(    (client_addr.sin_addr.s_addr != tRunPara.ip104Master1) 
				&& (client_addr.sin_addr.s_addr != tRunPara.ip104Master2)
				&& (client_addr.sin_addr.s_addr != tRunPara.ip104Master3)
				&& (client_addr.sin_addr.s_addr != tRunPara.ip104Master4) 
				&& (g_ip_net_maintain == 0)  // 如果维护工具已连接，任意104主站可以接入。
				&&(network0 != network1))	// 运行维护网络的104连接进来
			{
				net_104_close(net);
				rt_printf("主站IP不在允许范围内!\r\n");
				ip = (unsigned char *)&tRunPara.ip104Master1;
				rt_printf("允许IP1:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&tRunPara.ip104Master2;
				rt_printf("允许IP2:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&tRunPara.ip104Master3;
				rt_printf("允许IP3:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&tRunPara.ip104Master4;
				rt_printf("允许IP4:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&g_ip_net_maintain;
				rt_printf("允许IP5:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);				
				msleep(500);
				continue;
			}
		}
#endif	
		// 客户端已连接，处理客户端命令
		// 初始化接收FIFO
		rt_fifo_init(&g_net_104_fifo[net],g_net_104_buf[net],NET_104_BUF_SIZE);
		IEC104_Recv_Reset(&g_t104[net]);
		memcpy(g_t104[net].ip,(unsigned char *)&client_addr.sin_addr.s_addr,4);
		g_t104[net].LinkCountNet++;

		//接收帧超时初始化，超时设置为测试超时加确认超时后的2倍。
		recv_timeout=0;
		recv_timeout_set = (tRunPara.w104TestTime + tRunPara.w104AckTime)*2*10;

		// 循环处理接收数据
		while(1)
		{
			len = net_104_recv(net, g_net_104_buf_frame[net], NET_RECV_MAX);
			// 检查是否退出
			if(g_net_104_exit_flag[net])
			{
				// 关闭客户端
				net_104_close(net);
				// 关闭服务器
				rt_socket_close (sk_server);
				// complete_and_exit(&g_exit_completion_net_104[net], 0);
				return 0;
			}
			//是否重新初始化
			if(g_net_reinit[net] == NET_SOCKET_CLOSING)
			{
				// 关闭客户端
				net_104_close(net);
				
				// 关闭服务器
				rt_socket_close (sk_server);
				
				//置已经关闭标志
				g_net_reinit[net] = NET_SOCKET_CLOSED;
				//等待IP修改完成
				while(g_net_reinit[net] != NET_SOCKET_REINIT)
				{
					msleep(100);	
				}
				//置为初始化
				g_net_reinit[net] = NET_SOCKET_INIT;
				rt_printf("net_104_thread:链路重新初始化!\r\n");
				goto NET_BEGIN; 	
			}

			if(g_net_104_close_flag[net])
			{
				break;

			}

			if((len == -EAGAIN)||(len==-1))
			{
				if( rt_get_net_linkstatus(rt_get_netcard_id_from_socket(g_104_client[net] ))==1)
				{
					link_timeout++;
					if(link_timeout > RT_LINK_TIMEOUT*10) //100ms超时
					{
						rt_printf("net_104_thread: link down\r\n");
						link_timeout = 0;
						break;
					}
				}
				else
				{
					link_timeout=0;
				}

				// 接收帧超时
				recv_timeout++;
				if(recv_timeout>recv_timeout_set)
				{
					rt_printf ("net_104_thread:接收帧超时(value=%d,set=%d)\r\n",recv_timeout,recv_timeout_set);
					break;
				}
			}
			else if((len == 0)||(len<-1))
			{
				//调用recv时，如果返回0，则表示对端关闭；返回负数，表示出错
				rt_printf ("net_104_thread:rt_recv(ret=%d)\r\n",len);

				// TODO:以下休眠语句必须屏蔽，否则net_104_close会延时调用，
				// 导致主循环可以在此断开的socket上继续发送数据，引起系统异常。
				// msleep(100); 
				break;
			}
			else
			{
				int space;
				space = rt_fifo_space(&g_net_104_fifo[net]);
				if(space > len)
				{
					rt_fifo_put(&g_net_104_fifo[net],g_net_104_buf_frame[net],len);
					if(tRunPara.tNetPara[net].ethid<CFG_ETH_NUM_MAX)
						g_run_stu.led[CFG_UART_NUM_MAX*2+tRunPara.tNetPara[net].ethid]=1;
				}
				else
				{
					rt_printf ("net_104_thread:接收FIFO溢出(space=%d,len=%d)\r\n",space,len);
				}
				link_timeout=0;
			}
			// 接收数据
			
			// printf("g_t104[0].bSM2Data:%d,g_t104[0].bRecvOk:%d, g_link_comm.link_flag: %d, buflen: %d \n",g_t104[net].bSM2Data,g_t104[net].bRecvOk, g_link_comm.link_flag, len);
			
			while(g_t104[net].bSM2Data== false && g_t104[net].bRecvOk == false)
			{
				int j; //+++
				j=rt_fifo_get(&g_net_104_fifo[net],&buf,1); //+++
				//printf("----rt_fifo_get: %d \n",j); //+++
				//if(rt_fifo_get(&g_net_104_fifo[net],&buf,1))	
				if(j)
				{
					if(g_print_comm_raw && (g_print_port & (1<<(net+CFG_UART_NUM_MAX))))
					{
						rt_printf("%02x ",buf);
					}
					if(IEC104_Recv(&g_t104[net],buf))
					{
						//printf("----IEC104_Recv recv_timeout\n"); //+++
						// 如果接收到完整的一帧104报文(其它数据不清定时器，防止意外连接)，超时定时器清零。
						recv_timeout=0; 
					}
				}
				else
				{
					break;
				}
			}

		}

		// 关闭客户端socket
		net_104_close(net);
	}
#endif
	  while(1)
		{
		 rt_printf("net 104\r\n");
		 usleep(1000*1000);
	 }

	// 理论上，程序不会运行到这儿
	return 0;
}

int _net_104Client_thread(int net)
{
	struct sockaddr_in server_addr;

	//struct timeval timeout;
	//struct linger  ling;

	//SOCKET s; 
	int  s;

	int len,ret;
	unsigned int ip_server,link_count;
	int recv_timeout;
	unsigned char buf;
	unsigned char *ip;
//	int net = *pnet;

	while(1)
	{
		//rt_printf("BEGIN ---------[ %d ]	 [ %s ] \r\n",__LINE__,__func__);
	BEGIN:
		link_count = 0;
		// 检查级联IP是否设置

		ip_server =  tRunPara.ip104Master[net];
		while(1)
		{
			ip_server =  tRunPara.ip104Master[net];

//			ip_server = inet_addr("192.168.9.57");
			if(ip_server)
			{
				break;
			}

			// 检查是否退出
			if(g_net_104_exit_flag[net])
			{
//				rt_printf_time("net_104link_thread exit.\r\n");
				// complete_and_exit(&g_exit_completion_net_104[net], 0);
				return 0;
			}
			// 1秒钟检查一次
			msleep(1000);
		}

	  ip = (unsigned char *)&ip_server;
//		rt_printf_time("104连接服务器开始(%d):ip=%d.%d.%d.%d!\r\n",net,ip[0],ip[1],ip[2],ip[3]);
		//printf("104 conect ip=%x\n",ip_server);

		// 创建socket
		//s = rt_socket(AF_INET, SOCK_STREAM, 0);
		s = socket(AF_INET, SOCK_STREAM, 0);
		if (s == RT_SOCKET_ERR)
		{
			RT_PRINTF_POSITION();
			return -1;
		}
		// 服务器端填充sockaddr结构
		memset (&server_addr, 0, sizeof (struct sockaddr_in));
		server_addr.sin_family = AF_INET;

		//server_addr.sin_addr.s_addr = htonl (ip_server);
		server_addr.sin_addr.s_addr = ip_server;

		//server_addr.sin_port = htons (tRunPara.w104Port);
		server_addr.sin_port = htons(2404);


		// 连接服务器，没有连接成功不退出
		while(1)
		{

//			ret = rt_connect(s,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in));
			ret = connect(s,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in));
			//printf("ret is %d\n",ret);
#if 0
			// 检查是否退出
			if(g_net_104_exit_flag[net])
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				rt_printf_time("net_104_thread exit(rt_recv).\r\n");
				// complete_and_exit(&g_exit_completion_net_104[net], 0);
				return 0;
			}

			// 检查服务器是否变更
			if(ip_server != tRunPara.ip104Master[net])
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				ip = (unsigned char *)&tRunPara.ip104Master[net];
				rt_printf_time("主站服务器变更(%d):ip=%d.%d.%d.%d!\r\n",net,ip[0],ip[1],ip[2],ip[3]);				
			
				goto BEGIN;
			}
#endif
			if (ret == 0)
			{
				g_net_104_close_flag[net] = 0;
				g_link104_init_ok[net] = 0; 	
				g_104_client[net] = s;
				g_t104[net].bClientStart=false;
				link_count++;
				//rt_printf_time("104连接服务器成功(通道=%d,连接计数=%d):ip=%d.%d.%d.%d!\r\n",net,link_count,ip[0],ip[1],ip[2],ip[3]);
				printf("104 connected ok +++++++ok\n");
				break;
			}

			// 1秒钟连接一次
			msleep(1000);
		}
#if 0
		// 设置接收超时
		timeout.tv_sec	= 0;
		timeout.tv_usec = 100000;
		rt_setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout ,sizeof(struct timeval));
		
		// 设置关闭延时
		ling.l_onoff = 1;
		ling.l_linger = 0;
		rt_setsockopt(s,SOL_SOCKET,SO_LINGER,(char *)&ling ,sizeof(struct linger));

		// 初始化FIFO
		rt_fifo_init(&g_net_104_fifo[net],g_net_104_buf[net],NET_104_BUF_SIZE);

#endif
		// 处理接收
		recv_timeout = 0;
		while(1)
		{
			len = rt_recv (s, g_net_104_buf_frame[net], NET_RECV_MAX, 0);
					printf("recv data : %s \r\n",g_net_104_buf_frame[net]);
			// 检查是否退出
			if(g_net_104_exit_flag[net]) 
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				rt_printf_time("net_104client_thread exit(rt_recv).\r\n");
				// complete_and_exit(&g_exit_completion_net_104[net], 0);
				return 0;
			}


			// 检查服务器是否变更
			if(ip_server != tRunPara.ip104Master[net])
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				rt_printf_time("104服务器变更(%d):ip=%d.%d.%d.%d!\r\n",net,ip[0],ip[1],ip[2],ip[3]);
				goto BEGIN;
			}

			// 应用程序主动关闭
			if(g_net_104_close_flag[net])
			{
				break;
			
			}

			if(len == -EAGAIN)
			{
				// 超时
				recv_timeout++;
				if(recv_timeout>300)  // 超时30s，端口未收到数据，关闭端口
				{
					rt_printf_time("104客户端30S超时关闭(net=%d)\r\n",net);
					break;
				}
			}
			else if (len <= 0)
			{
				//调用recv时，如果返回0，则表示对端关闭；返回负数，表示出错
				rt_printf_time ("104客户端关闭(net=%d,ret=%d)\r\n",net,len);
				msleep(100);
				break;
			}
			else
			{
				rt_fifo_put(&g_net_104_fifo[net],g_net_104_buf_frame[net],len);
				recv_timeout=0; 	//超时计数器清零
				if(tRunPara.tNetPara[net].ethid<CFG_ETH_NUM_MAX)
					g_run_stu.led[CFG_UART_NUM_MAX*2+tRunPara.tNetPara[net].ethid]=1;				
			}
			
			// 接收数据
			while(g_t104[net].bSM2Data== false && g_t104[net].bRecvOk == false)
			{
				if(rt_fifo_get(&g_net_104_fifo[net],&buf,1))
				{
					IEC104_Recv(&g_t104[net],buf);
				}
				else
				{
					break;
				}
			}

			// msleep(100);
		}

		// 关闭客户端socket
		g_104_client[net] = RT_SOCKET_ERR;
		rt_socket_close (s);
	//	rt_printf_time ("net_104link_thread:rt_recv(ret=%d)\r\n",len);

	}

	// 理论上，程序不会运行到这儿
	return 0;
}

#else

/*------------------------------- 头文件 --------------------------------------
*/
#include "head.h"
 #include <linux/delay.h>

/*------------------------------- 宏定义 --------------------------------------
*/
#define NET_104_BUF_SIZE   16384


/*------------------------------ 类型结构 -------------------------------------
*/


/*------------------------------ 全局变量 -------------------------------------
*/
static struct task_struct * g_ts_104[IEC104_TOTAL_SOCKETS];
static SOCKET g_104_client[IEC104_TOTAL_SOCKETS];

static unsigned char g_net_104_buf_frame[IEC104_TOTAL_SOCKETS][NET_RECV_MAX];  // 以太网接收缓冲区
static unsigned char g_net_104_buf[IEC104_TOTAL_SOCKETS][NET_104_BUF_SIZE];  // 以太网接收缓冲区
static struct rt_fifo	g_net_104_fifo[IEC104_TOTAL_SOCKETS];

static volatile int g_net_reinit[CFG_ETH_MAX_LOGIC]={NET_SOCKET_INIT};//网络重新初始化标志.0表示不用重新初始化，1表示需要重新初始化
static struct semaphore net_r_lock[CFG_ETH_MAX_LOGIC];		//接收锁
static struct semaphore net_s_lock[CFG_ETH_MAX_LOGIC]; 		//发送锁

static int g_net_104_close_flag[CFG_ETH_MAX_LOGIC];
static int g_net_104_exit_flag[CFG_ETH_MAX_LOGIC];

static struct completion g_exit_completion_net_104[CFG_ETH_MAX_LOGIC];

extern u32	g_ip_net_maintain;	// 104维护工具调试客户端地址

/*------------------------------ 函数声明 -------------------------------------
*/
int _net_104_thread(IEC104_DEF *pt104);

//设置socket关闭标志并等待socket关闭完成
void net_104_set_sock_closing(int no)
{
    //if(no >=  g_net_num) return;

    g_net_reinit[no] = NET_SOCKET_CLOSING; //置关闭标志

    if(!tRunPara.b104Client)
    {   
	    int count=0;
        //等待关闭完成
        while(g_net_reinit[no] != NET_SOCKET_CLOSED)
        {
            msleep(20);
            if(++count>150)
            {
             	rt_printf("104 client socket close fail!!!\r\n");
             	return;
            }
        }
    }

}

//设置socket重新创建标志
void net_104_set_sock_initflag(int no)
{
//	if(no >=  g_net_num) return;
	
	if(g_net_reinit[no] == NET_SOCKET_CLOSED)
	{
		g_net_reinit[no] = NET_SOCKET_REINIT;	
	}
	
}

/**************************************************************************
函数名称：Net_Init
函数版本：1.00 
作者：   
创建日期：2009.1.8    
函数功能说明：以太网初始化
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/
void Net_Init(void)
{
	unsigned char mac[6];
	unsigned char ip[4];
	unsigned char mask[4];
	unsigned char gw[4];
	unsigned char routenet[4];
	unsigned char routenetmask[4];
	unsigned char routegate[4];	
//	char * acteth;
	int i,j;
	char tmp[16];
	int ret = 0;
	int gateflag = 0;

	if(tRunPara.w104K == 0)
	{
		if(pRunSet->bTT_SoeResumeComm || pRunSet->bTT_SoeResumePower)
		{
			rt_printf("定值参数错误：SOE通讯续传、SOE上电续传时参数104 K值不能为0.\r\n");
			rt_err_set(ERR_CODE_INIT_SOFTWARE,0);
		}
	}

	#if 0
	int debug_port;
	acteth = env_get_info(ENV_ETHACT);
	if(acteth != NULL)
	{
		if(strcmp(acteth,"FEC0") == 0)
		{
			debug_port = 0;	
		}
		else if(strcmp(acteth,"FEC1") == 0)
		{
			debug_port = 1;	
		}
		else if(strcmp(acteth,"DM9000") == 0)
		{
			debug_port = 2;	
		} 
		else 
		{
			debug_port = 0;			
		}	
		
	}
	else 
	{
		debug_port = 0;			
			
	}
	#endif
//	if(acteth != NULL && strcmp(acteth,"DM9000") == 0)
//	{
//		debug_port = 2;
//	}
//	else
//	{
//		debug_port = 0;
//	}



	//for(i=0;i<g_net_num;i++)
	for(i=0;i<CFG_ETH_MAX_LOGIC;i++)
	{
		//没有改变参数，不用初始化
		if(!tRunPara.tNetPara[i].bInit)
		{
			//104配置参数有修改,需关闭socket重新初始化
			if(tRunPara.sock_104_flag)
			{
				net_104_set_sock_initflag(i);	
			}		
		
			continue;
		}
		gateflag = 1;
		tRunPara.tNetPara[i].bInit=false;
		
		// 设置接口MAC地址
		if(rt_if_sz2mac(env_get_info(ENV_NET1MAC+i),mac)< 0)
		{
			mac[0] = 'H';
			mac[1] = 'G';
			mac[2] = (BYTE)((tRunPara.tNetPara[i].wIp>>24)&0xff);
			mac[3] = (BYTE)((tRunPara.tNetPara[i].wIp>>16)&0xff);
			mac[4] = (BYTE)((tRunPara.tNetPara[i].wIp>>8)&0xff);
			mac[5] = (BYTE)((tRunPara.tNetPara[i].wIp>>0)&0xff);
		
		}

		// 设置IP	
		ip[0] = (BYTE)((tRunPara.tNetPara[i].wIp>>24)&0xff);
		ip[1] = (BYTE)((tRunPara.tNetPara[i].wIp>>16)&0xff);
		ip[2] = (BYTE)((tRunPara.tNetPara[i].wIp>>8)&0xff);
		ip[3] = (BYTE)((tRunPara.tNetPara[i].wIp>>0)&0xff);
	
		// 设置MASK
		mask[0] =  (BYTE)((tRunPara.tNetPara[i].wMask>>24)&0xff);
		mask[1] =  (BYTE)((tRunPara.tNetPara[i].wMask>>16)&0xff);
		mask[2] = (BYTE)((tRunPara.tNetPara[i].wMask>>8)&0xff);
		mask[3] = (BYTE)((tRunPara.tNetPara[i].wMask>>0)&0xff);

#if (1)
        printf("[%s:%d]\r\n", __func__, __LINE__);
        if(tRunPara.tNetPara[i].old_ethid !=  tRunPara.tNetPara[i].ethid)   //网络号已改变且为物理网卡时
        {
            BYTE count;

            if((int)tRunPara.tNetPara[i].old_index == 0)
            {
                rt_if_down(tRunPara.tNetPara[i].old_ethid); //此时卸载当前网卡所有P 比如eth0 eth0:2 eth0:3
                //rt_printf("down eth%d\r\n",tRunPara.tNetPara[i].old_ethid);
            }
            else if((int)tRunPara.tNetPara[i].old_index > 0)
            {
                rt_if_down2(tRunPara.tNetPara[i].old_ethid, tRunPara.tNetPara[i].old_index);
               // rt_printf("down eth%d:%d\r\n",tRunPara.tNetPara[i].old_ethid,tRunPara.tNetPara[i].old_index);
            }

            for(count=i+1; count<CFG_ETH_MAX_LOGIC; count++) //物理网卡被更新 相应的之前的物理网卡和虚拟网卡都需要重新配置
                if((tRunPara.tNetPara[i].ethid==tRunPara.tNetPara[count].old_ethid)
                   ||(tRunPara.tNetPara[i].old_ethid==tRunPara.tNetPara[count].ethid))
                {
                    tRunPara.tNetPara[count].bInit=true;
                    if((int)tRunPara.tNetPara[count].old_index > 0)  //若关联的为虚拟网卡则默认不需要进行投退
                    {
						rt_if_down2(tRunPara.tNetPara[count].old_ethid, tRunPara.tNetPara[count].old_index);
						//rt_printf("down eth%d:%d\r\n",tRunPara.tNetPara[count].old_ethid,tRunPara.tNetPara[count].old_index);
                        tRunPara.tNetPara[count].old_index = 0;
 
                    }
                    else
                    {
                        rt_if_down(tRunPara.tNetPara[count].old_ethid); //此时卸载当前网卡所有P 比如eth0 eth0:2 eth0:3
                        //rt_printf("down eth%d\r\n",tRunPara.tNetPara[count].old_ethid);
                    }
                }

        }
        else if((int)tRunPara.tNetPara[i].old_index > 0)   //网络号未改变时的  虚拟网卡
        {
            rt_if_down2(tRunPara.tNetPara[i].old_ethid, tRunPara.tNetPara[i].old_index);
            //rt_printf("down eth%d:%d\r\n",tRunPara.tNetPara[i].old_ethid,tRunPara.tNetPara[i].old_index);
        }

#else
        //检查是否需要关闭虚拟网卡
        if((int)tRunPara.tNetPara[i].old_index > 0)
        {
            rt_if_down2(tRunPara.tNetPara[i].old_ethid, tRunPara.tNetPara[i].old_index);
        }
#endif
        //获取配置相同的ethid有多少个
        ret=get_ethcnt(i, tRunPara.tNetPara[i].ethid);

        //没有的话，使用物理的
        if(ret==0)
        {

            // 设置网络参数
            net_if_set((int)tRunPara.tNetPara[i].ethid,mac,ip, mask);
            tRunPara.tNetPara[i].index = 0;

			 //rt_printf_time("ret = %d, ethID = %d\r\n",ret,tRunPara.tNetPara[i].ethid);
		}
		else  //有的话使用虚拟的
		{
			 #if (1)
             printf("[%s:%d]\r\n", __func__, __LINE__);
			 net_if_set2((int)tRunPara.tNetPara[i].ethid, ret, 0, ip, mask);	
			 tRunPara.tNetPara[i].index = ret;
			 #else
			 net_if_set2((int)tRunPara.tNetPara[i].ethid, i+1, 0, ip, mask);
			 tRunPara.tNetPara[i].index = i+1;
			 #endif
			 
			 

			 
			 //rt_printf_time("Xnet = %d,ip=%x, ethID = %d, ret = %d\r\n",tRunPara.tNetPara[i].index,ip[3],tRunPara.tNetPara[i].ethid,ret);
		}


		 tRunPara.tNetPara[i].old_ethid=  tRunPara.tNetPara[i].ethid;
		 tRunPara.tNetPara[i].old_index=  tRunPara.tNetPara[i].index;
		 


		// 如果是调试串口，不初始化
		//if(i == debug_port)
		if(i==(CFG_ETH_MAX_LOGIC-1))
		{
			//设置IP环境变量
			if(tRunPara.tNetPara[i].changed & 0x01)
			{
				sprintf(tmp, "%d.%d.%d.%d",( tRunPara.tNetPara[i].wIp>>24)&0xff, (tRunPara.tNetPara[i].wIp>>16)&0xff, (tRunPara.tNetPara[i].wIp>>8)&0xff, (tRunPara.tNetPara[i].wIp&0xff));
				env_setenv("ipaddr", tmp); 
			}
			
			//设置Gate环境变量
			if(tRunPara.tNetPara[i].changed & 0x02)
			{
				sprintf(tmp, "%d.%d.%d.%d", ( tRunPara.tNetPara[i].wGate>>24)&0xff, (tRunPara.tNetPara[i].wGate>>16)&0xff, (tRunPara.tNetPara[i].wGate>>8)&0xff, (tRunPara.tNetPara[i].wGate&0xff));
				if(tRunPara.tNetPara[i].wGate)
					env_setenv("gatewayip", tmp); 
			}		

			//设置Mask环境变量
			if(tRunPara.tNetPara[i].changed & 0x04)
			{
				sprintf(tmp, "%d.%d.%d.%d", ( tRunPara.tNetPara[i].wMask>>24)&0xff, (tRunPara.tNetPara[i].wMask>>16)&0xff, (tRunPara.tNetPara[i].wMask>>8)&0xff, (tRunPara.tNetPara[i].wMask&0xff));
				env_setenv("netmask", tmp); 
			}	

			//设置ethact环境变量
			if(tRunPara.tNetPara[i].changed & 0x40)
			{
				if(tRunPara.tNetPara[i].ethid >= 2)
				{
					sprintf(tmp, "%s", "DM9000");	
				}
				else
				{
					sprintf(tmp, "FEC%d", (int)tRunPara.tNetPara[i].ethid);	
				}
				
				env_setenv("ethact", tmp); 

			}			
			//continue;
		
		}



		//网段
		routenet[0] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>24)&0xff);
		routenet[1] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>16)&0xff);
		routenet[2] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>8)&0xff);
		routenet[3] = (BYTE)((tRunPara.tNetPara[i].wRouteNet>>0)&0xff);	

		//网段掩码
		routenetmask[0] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>24)&0xff);
		routenetmask[1] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>16)&0xff);
		routenetmask[2] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>8)&0xff);
		routenetmask[3] = (BYTE)((tRunPara.tNetPara[i].wRouteNetMask>>0)&0xff);

		//网关
		routegate[0] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>24)&0xff);
		routegate[1] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>16)&0xff);
		routegate[2] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>8)&0xff);
		routegate[3] = (BYTE)((tRunPara.tNetPara[i].wRouteGate>>0)&0xff);		
		
		net_route_set(routenet, routenetmask, routegate);
		
		//g_net_reinit[i] = 1;//置重新初始化标志 
		net_104_set_sock_initflag(i);
		net_debug_set_sock_initflag();
		net_maintain_set_sock_initflag();
#if 0
		// 得到并打印新的网络参数
	//	net_if_get(i,mac,ip,mask);
		rt_printf("new mac: %02x:%02x:%02x:%02x:%02x:%02x\r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
		rt_printf("new ip:%d.%d.%d.%d\r\n",ip[0],ip[1],ip[2],ip[3]);
		rt_printf("new mask:%d.%d.%d.%d\r\n",mask[0],mask[1],mask[2],mask[3]);
		rt_printf("new gw:%d.%d.%d.%d\r\n",gw[0],gw[1],gw[2],gw[3]);
#endif
	}


	ret = 0;
	//查找是否关闭物理网卡
	for(i=0;i<g_net_num;i++)
	{
		for(j=0;j<CFG_ETH_MAX_LOGIC;j++)
		{
			if(tRunPara.tNetPara[j].ethid == i)
			{
				ret++; //虚拟网卡使用物理网卡计数
			}
		}

		//没有虚拟网卡使用物理网卡
		if(ret==0)
		{
			rt_if_down(i);
		}

		ret = 0;
	}

	
	// 设置网关
	gw[0] =  (BYTE)((tRunPara.tNetPara[0].wGate>>24)&0xff);
	gw[1] =  (BYTE)((tRunPara.tNetPara[0].wGate>>16)&0xff);
	gw[2] =  (BYTE)((tRunPara.tNetPara[0].wGate>>8)&0xff);
	gw[3] =  (BYTE)((tRunPara.tNetPara[0].wGate>>0)&0xff);

	// 如果地址是默认的0.0.0.0，说明用户不需要网关，
	// 不重设网关，使uboot环境变量中的网关有效，方便调试。
	if(gw[0]==0 && gw[1]==0 && gw[2]==0 && gw[3]==0)
	{
		return;
	}

	if(gateflag)
	{
		net_gateway_set(gw);
	}
	
	return;
}


    
/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/
int net_104_init(void)
{
	int net;
	char buf[32];
	struct sched_param sp;
	pid_t pid;

	IEC104_Init();

	for(net=0; net<CFG_ETH_MAX_LOGIC; net++)
	{
		g_104_client[net] = RT_SOCKET_ERR;
		
		init_completion(&g_exit_completion_net_104[net]);
		g_net_reinit[net] = 0; //初始化标志
		init_MUTEX(&net_r_lock[net]);//初始化接收锁
		init_MUTEX(&net_s_lock[net]);//初始化发送锁
		// 如果接口不正常，不初始化

		if(tRunPara.tNetPara[net].index == 0)
		{
			if(rt_if_ip_get(tRunPara.tNetPara[net].ethid, buf)!=0) 
			{
				continue;
			}
				
		}
		else
		{
			if(rt_if_ip_get2(tRunPara.tNetPara[net].ethid, tRunPara.tNetPara[net].index, buf)!=0)
			{
				continue;
			}

		}		

		// 运行应用104线程
		sprintf(buf,"net_104_%d",net);
		pid = kernel_thread((int (*)(void *))_net_104_thread,&g_t104[net],CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
		g_ts_104[net] = find_task_by_vpid(pid);
		if(IS_ERR(g_ts_104[net]))
		{
			printk("ts=%p\r\n",g_ts_104[net]);
			g_ts_104[net] = NULL;
			return -1;
		}

		// 设置调度策略和优先级
		sp.sched_priority = 8;
		sched_setscheduler(g_ts_104[net],SCHED_FIFO,&sp);
		// 设置进程名字
		set_task_comm(g_ts_104[net], buf);	
	}

	return 0;
}


int net_104_exit(void)
{
	int net;
	 
	for(net=0; net<CFG_ETH_MAX_LOGIC; net++)
	{
		if(g_ts_104[net] != NULL)
		{
			//kthread_stop(g_ts_104[net]);
			g_net_104_exit_flag[net] = 1;
			wait_for_completion(&g_exit_completion_net_104[net]);
		}
	}

	return 0;
}

int net_104_send_ext(int net,unsigned char *buf,int len)
{
	int ret = 0;
	int ch = net+CFG_UART_NUM_MAX;

	if(g_print_comm_raw && (g_print_port & (1<<ch)))
	{
		char sz[16];
		sprintf(sz,"\r\nTX[%d]:",ch);
		print_mem(sz,buf,len);
		rt_printf("\r\n");
	}

	down(&net_s_lock[net]);	
	if(g_104_client[net] != RT_SOCKET_ERR)
	{
		ret = rt_send(g_104_client[net],buf,len,0);
	}
	up(&net_s_lock[net]);

	if(ret < 0)
	{
		rt_printf("net_104_send:ret=%d.\r\n",ret);
	}
	return	ret;
}



int net_104_send(int net,unsigned char *buf,int len)
{
	int ret = 0;
	u8 ti,cot,se;
	u8 *out;
	if(pRunSet->bTT_ESAM)
	{
		iec_GetMsgInfo(buf,len,&ti,&cot,&se,false);
		len =  sec_encrpt_iec(ti,cot,se,buf,len,&out);
		if(len > 0)
		{
			ret=net_104_send_ext(net,out, len);
		}
	}
	else
	{
		ret=net_104_send_ext(net,buf, len);
	}
	return ret;
}

static int net_104_recv(int net, unsigned char *buf,int len)
{
	int ret = 0;
	down(&net_r_lock[net]);	
	if(g_104_client[net] != RT_SOCKET_ERR)
	{
		ret = rt_recv (g_104_client[net], (void *)buf, NET_RECV_MAX, MSG_DONTWAIT);
	}

	up(&net_r_lock[net]);
	return	ret;
}

void net_104_close(int net)
{
	down(&net_r_lock[net]);
	down(&net_s_lock[net]);

	if(g_104_client[net] != RT_SOCKET_ERR)
	{
	
		rt_socket_close (g_104_client[net]);
		g_104_client[net] = RT_SOCKET_ERR;	
	}
	
	g_net_104_close_flag[net] = 0;

	up(&net_s_lock[net]);
	up(&net_r_lock[net]); 	

}

void net_104_close_flag(int net)
{
	down(&net_r_lock[net]);
	down(&net_s_lock[net]);
	
	if(g_104_client[net] != RT_SOCKET_ERR)	
	{
		g_net_104_close_flag[net] = 1;
	}
	
	up(&net_s_lock[net]);
	up(&net_r_lock[net]); 	
}

int net_104_is_connect(int net)
{
	if((g_104_client[net] == RT_SOCKET_ERR) || g_net_104_close_flag[net])
	{
		return 0;
	}

	return 1;
}


/*------------------------------ 内部函数 -------------------------------------
内部函数以下划线‘_’开头，不需要检查参数的合法性.
*/
extern int _net_104Client_thread(int net);
int _net_104_thread(IEC104_DEF *pt104)
{
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;

	struct linger  ling;

	SOCKET sk_server,sk_tmp ; 

	int net;
	int sin_size;
	int len,ret;
	unsigned char *ip;
	unsigned int ip_server;
	unsigned int recv_timeout,recv_timeout_set;
	unsigned int link_timeout=dTCounter;
	unsigned char buf;
	u16 w104Port;
	
	if(tRunPara.b104Client)  // 104采用客户端
	{
		net = pt104->cNetIndex;
		_net_104Client_thread(net);
		return 0;
	}

NET_BEGIN:
	net = pt104->cNetIndex;

	// 服务器端开始建立socket描述符
	//sk_server = rt_socket(AF_INET, SOCK_STREAM, 0);
	sk_server = rt_socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0);//noted by sunxi: 20221212 设为非阻塞型
	if (sk_server == RT_SOCKET_ERR)
	{
		RT_PRINTF_POSITION();
		g_ts_104[net] = NULL;
		return -1;
	}

	// 服务器端填充sockaddr结构
	memset (&server_addr, 0, sizeof (struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	//rt_if_ip_get(net,(unsigned char *)&ip_server);
	//ret=get_ethcnt(net, tRunPara.tNetPara[net].ethid);


	//IP在物理网卡上
	if( tRunPara.tNetPara[net].index == 0)
	{
		rt_if_ip_get(tRunPara.tNetPara[net].ethid, (unsigned char *)&ip_server);	
		w104Port = tRunPara.w104Port; // 网络1、2使用可变端口，保证级联时不冲突。
	}
	else  //IP在虚拟网卡上
	{
		//从虚拟网卡获取IP地址
		rt_printf("%s 获取虚拟网卡IP地址:ethid=%d,index=%d\r\n",__func__,tRunPara.tNetPara[net].ethid,tRunPara.tNetPara[net].index);
		rt_if_ip_get2(tRunPara.tNetPara[net].ethid, tRunPara.tNetPara[net].index, (unsigned char *)&ip_server);	
		w104Port = NET_104_PORT; // 调试网络使用固定的2404端口，保证维护工具可以连接。
	}


	server_addr.sin_addr.s_addr = htonl (ip_server);
	server_addr.sin_port = htons (w104Port);

	// 捆绑sockfd描述符
	ret = rt_bind (sk_server, (struct sockaddr *)(&server_addr), sizeof (struct sockaddr));
	if (ret < 0)
	{
		RT_PRINTF_POSITION();
		rt_socket_close (sk_server);
		g_ts_104[net] = NULL;
		
		return -2;
	}

	// 监听sockfd描述符
	ret = rt_listen (sk_server, 1);
	if (ret < 0)
	{
		RT_PRINTF_POSITION();
		rt_socket_close (sk_server);
		g_ts_104[net] = NULL;
		
		return -3;
	}

	// 设置关闭延时
	ling.l_onoff = 1;
	ling.l_linger = 0;
	rt_setsockopt(sk_server,SOL_SOCKET,SO_LINGER,(char *)&ling ,sizeof(struct linger));

	ip = (unsigned char *)&ip_server;
	//rt_printf("应用104线程已启动(IP:%d.%d.%d.%d,PORT:%d)。\r\n",ip[0],ip[1],ip[2],ip[3],NET_104_PORT);
	
	while(1)
	{
		msleep(100);//noted by sunxi: 20221212 设为非阻塞型
	
		// 服务器阻塞，直到客户程序建立连接
		sin_size = sizeof (struct sockaddr_in);
		sk_tmp = rt_accept (sk_server, (struct sockaddr*)(&client_addr), &sin_size);
		// 检查是否退出
		if(g_net_104_exit_flag[net])
		{
			// 关闭客户端
			net_104_close(net);
			// 关闭服务器
			rt_socket_close (sk_server);
			complete_and_exit(&g_exit_completion_net_104[net], 0);	
			return 0;
		}
		//是否重新初始化
		if(g_net_reinit[net] == NET_SOCKET_CLOSING)
		{
			// 关闭客户端
			net_104_close(net);
			// 关闭服务器
			rt_socket_close (sk_server);
			//置已经关闭标志
			g_net_reinit[net] = NET_SOCKET_CLOSED;
			//等待IP修改完成
			while(g_net_reinit[net] != NET_SOCKET_REINIT)
			{
				msleep(100);	
			}
			//置为初始化
			g_net_reinit[net] = NET_SOCKET_INIT;
			goto NET_BEGIN;		
		}
		//注意，用指针类型的socket接口，失败是返回NULL
		//而整数类型的socket接口,失败返回的是负数
		#ifdef RT_SOCKET_FD
		if (sk_tmp < 0)
		{
			//msleep(100);//noted by sunxi: 20221212 设为非阻塞型	
			// 超时
			continue;
		}
		#else
		if (sk_tmp == RT_SOCKET_ACCEPT_RST) 
		{
			//msleep(100);//noted by sunxi: 20221212 设为非阻塞型
			// 超时
			continue;			
		}
		#endif
		g_104_client[net] = sk_tmp;
		

		ip = (unsigned char *)&client_addr.sin_addr.s_addr;
		rt_printf("104 client[net=%d,s=%d] connect(ip=%d.%d.%d.%d)!\r\n", net ,sk_tmp,ip[0],ip[1],ip[2],ip[3]);

		
		
		// 检查是否主站IP
		if(tRunPara.ip104Master1 || tRunPara.ip104Master2 || tRunPara.ip104Master3 || tRunPara.ip104Master4)
		{
			u32 network0,network1;
			network0 = client_addr.sin_addr.s_addr & tRunPara.tNetPara[CFG_ETH_MAX_LOGIC-1].wMask;
			network1 = tRunPara.tNetPara[CFG_ETH_MAX_LOGIC-1].wIp & tRunPara.tNetPara[CFG_ETH_MAX_LOGIC-1].wMask;
			
			if(	   (client_addr.sin_addr.s_addr != tRunPara.ip104Master1) 
				&& (client_addr.sin_addr.s_addr != tRunPara.ip104Master2)
				&& (client_addr.sin_addr.s_addr != tRunPara.ip104Master3)
				&& (client_addr.sin_addr.s_addr != tRunPara.ip104Master4) 
				&& (g_ip_net_maintain == 0)  // 如果维护工具已连接，任意104主站可以接入。
				&&(network0 != network1)) 	// 运行维护网络的104连接进来
			{
				net_104_close(net);
				rt_printf("主站IP不在允许范围内!\r\n");
				ip = (unsigned char *)&tRunPara.ip104Master1;
				rt_printf("允许IP1:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&tRunPara.ip104Master2;
				rt_printf("允许IP2:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&tRunPara.ip104Master3;
				rt_printf("允许IP3:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&tRunPara.ip104Master4;
				rt_printf("允许IP4:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);
				ip = (unsigned char *)&g_ip_net_maintain;
				rt_printf("允许IP5:%d.%d.%d.%d)!\r\n",ip[0],ip[1],ip[2],ip[3]);				
				msleep(500);
				continue;
			}
		}
	
		// 客户端已连接，处理客户端命令
		// 初始化接收FIFO
		rt_fifo_init(&g_net_104_fifo[net],g_net_104_buf[net],NET_104_BUF_SIZE);
		IEC104_Recv_Reset(&g_t104[net]);
		memcpy(g_t104[net].ip,(unsigned char *)&client_addr.sin_addr.s_addr,4);
		g_t104[net].LinkCountNet++;

		//接收帧超时初始化，超时设置为测试超时加确认超时后的2倍。
		recv_timeout=dTCounter;
		recv_timeout_set = (tRunPara.w104TestTime + tRunPara.w104AckTime)*2*T_1s;

		// 循环处理接收数据
		while(1)
		{
			msleep(2);//noted by sunxi: 20221212 设为非阻塞型
			
			len = net_104_recv(net, g_net_104_buf_frame[net], NET_RECV_MAX);
			// 检查是否退出
			if(g_net_104_exit_flag[net])
			{
				// 关闭客户端
				net_104_close(net);
				// 关闭服务器
				rt_socket_close (sk_server);
				complete_and_exit(&g_exit_completion_net_104[net], 0);	
				return 0;
			}
			//是否重新初始化
			if(g_net_reinit[net] == NET_SOCKET_CLOSING)
			{
				// 关闭客户端
				net_104_close(net);
				
				// 关闭服务器
				rt_socket_close (sk_server);
				
				//置已经关闭标志
				g_net_reinit[net] = NET_SOCKET_CLOSED;
				//等待IP修改完成
				while(g_net_reinit[net] != NET_SOCKET_REINIT)
				{
					msleep(100);	
				}
				//置为初始化
				g_net_reinit[net] = NET_SOCKET_INIT;
				rt_printf("net_104_thread:链路重新初始化!\r\n");
				goto NET_BEGIN;		
			}

			if(g_net_104_close_flag[net])
			{
				break;
			}

			if(len == -EAGAIN)
			{
				if( rt_get_net_linkstatus(rt_get_netcard_id_from_socket(g_104_client[net] ))==1)
				{
					if((dTCounter - link_timeout)>RT_LINK_TIMEOUT*T_1s) //500ms超时
					{
						rt_printf("net_104_thread: link down\r\n");
						link_timeout = dTCounter;
						break;	
					}
				}
				else
				{			
					link_timeout=dTCounter;
				}

				// 接收帧超时
				if((dTCounter - recv_timeout)>recv_timeout_set)
				{
					rt_printf ("net_104_thread:接收帧超时(value=%d,set=%d)\r\n",recv_timeout,recv_timeout_set);
					break;
				}
			}
			else if (len <= 0)
			{
				//调用recv时，如果返回0，则表示对端关闭；返回负数，表示出错
				rt_printf ("net_104_thread:rt_recv(ret=%d)\r\n",len);

				// TODO:以下休眠语句必须屏蔽，否则net_104_close会延时调用，
				// 导致主循环可以在此断开的socket上继续发送数据，引起系统异常。
				// msleep(100); 
				break;
			}
			else
			{
				int space;
				space = rt_fifo_space(&g_net_104_fifo[net]);
				if(space > len)
				{
					rt_fifo_put(&g_net_104_fifo[net],g_net_104_buf_frame[net],len);
					if(tRunPara.tNetPara[net].ethid<CFG_ETH_NUM_MAX)
						g_run_stu.led[CFG_UART_NUM_MAX*2+tRunPara.tNetPara[net].ethid]=1;
				}
				else
				{
					rt_printf ("net_104_thread:接收FIFO溢出(space=%d,len=%d)\r\n",space,len);
				}
				link_timeout=dTCounter;
			}
			// 接收数据
			while(g_t104[net].bSM2Data== false && g_t104[net].bRecvOk == false)
			{
				if(rt_fifo_get(&g_net_104_fifo[net],&buf,1))
				{
					if(g_print_comm_raw && (g_print_port & (1<<(net+CFG_UART_NUM_MAX))))
					{
						rt_printf("%02x ",buf);
					}
					if(IEC104_Recv(&g_t104[net],buf))
					{
						// 如果接收到完整的一帧104报文(其它数据不清定时器，防止意外连接)，超时定时器清零。
						recv_timeout=dTCounter; 
					}
				}
				else
				{
					break;
				}
			}


 		}

		// 关闭客户端socket
		net_104_close(net);
	}

	// 理论上，程序不会运行到这儿
	return 0;
}

int _net_104Client_thread(int net)
{
	struct sockaddr_in server_addr;

	struct linger  ling;

	SOCKET s; 

	int len,ret;
	unsigned int ip_server,link_count;
	unsigned int recv_timeout;
	unsigned char buf;
	unsigned char *ip;
//	int net = *pnet;
	while(1)
	{
BEGIN:
		link_count = 0;
		// 检查级联IP是否设置
		while(1)
		{
			ip_server =  tRunPara.ip104Master[net];
			if(ip_server)
			{
				break;
			}
			
			// 检查是否退出
			if(g_net_104_exit_flag[net])
			{
//				rt_printf_time("net_104link_thread exit.\r\n");
				complete_and_exit(&g_exit_completion_net_104[net], 0);	
				return 0;
			}
		
			// 1秒钟检查一次
			msleep(1000);
		}
		ip = (unsigned char *)&ip_server;
		rt_printf_time("104连接服务器开始(%d):ip=%d.%d.%d.%d!\r\n",net,ip[0],ip[1],ip[2],ip[3]);


		// 创建socket
		s = rt_socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0);
		if (s == RT_SOCKET_ERR)
		{
			RT_PRINTF_POSITION();
			return -1;
		}
		// 服务器端填充sockaddr结构
		memset (&server_addr, 0, sizeof (struct sockaddr_in));
		server_addr.sin_family = AF_INET;
		server_addr.sin_addr.s_addr = htonl (ip_server);
		server_addr.sin_port = htons (tRunPara.w104Port);

		// 连接服务器，没有连接成功不退出
		while(1)
		{
			ret = rt_connect(s,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in));
			
			// 检查是否退出
			if(g_net_104_exit_flag[net])
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				rt_printf_time("net_104_thread exit(rt_recv).\r\n");
				complete_and_exit(&g_exit_completion_net_104[net], 0);	
				return 0;
			}

			// 检查服务器是否变更
			if(ip_server != tRunPara.ip104Master[net])
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				ip = (unsigned char *)&tRunPara.ip104Master[net];
				rt_printf_time("主站服务器变更(%d):ip=%d.%d.%d.%d!\r\n",net,ip[0],ip[1],ip[2],ip[3]);				
			
				goto BEGIN;
			}

			if (ret == 0)
			{
				g_net_104_close_flag[net] = 0;
				g_link104_init_ok[net] = 0;		
				g_104_client[net] = s;
				g_t104[net].bClientStart=false;
				link_count++;
				rt_printf_time("104连接服务器成功(通道=%d,连接计数=%d):ip=%d.%d.%d.%d!\r\n",net,link_count,ip[0],ip[1],ip[2],ip[3]);
				break;
			}

			// 1秒钟连接一次
			msleep(1000);
		}
	
		// 设置关闭延时
		ling.l_onoff = 1;
		ling.l_linger = 0;
		rt_setsockopt(s,SOL_SOCKET,SO_LINGER,(char *)&ling ,sizeof(struct linger));

		// 初始化FIFO
		rt_fifo_init(&g_net_104_fifo[net],g_net_104_buf[net],NET_104_BUF_SIZE);

		// 处理接收
		
		recv_timeout=dTCounter;
		while(1)
		{
			msleep(2);//noted by sunxi: 20221212 设为非阻塞型
			
			len = rt_recv (s, g_net_104_buf_frame[net], NET_RECV_MAX, MSG_DONTWAIT);

			// 检查是否退出
			if(g_net_104_exit_flag[net]) 
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				rt_printf_time("net_104client_thread exit(rt_recv).\r\n");
				complete_and_exit(&g_exit_completion_net_104[net], 0);	
				return 0;
			}


			// 检查服务器是否变更
			if(ip_server != tRunPara.ip104Master[net])
			{
				// 关闭客户端
				g_104_client[net] = RT_SOCKET_ERR;
				rt_socket_close (s);
				rt_printf_time("104服务器变更(%d):ip=%d.%d.%d.%d!\r\n",net,ip[0],ip[1],ip[2],ip[3]);
				goto BEGIN;
			}

			// 应用程序主动关闭
			if(g_net_104_close_flag[net])
			{
				break;
			
			}

			if(len == -EAGAIN)
			{
				// 超时
				if((dTCounter -  recv_timeout)>30*T_1s)  // 超时30s，端口未收到数据，关闭端口
				{
					rt_printf_time("104客户端30S超时关闭(net=%d)\r\n",net);
					break;
				}
			}
			else if (len <= 0)
			{
				//调用recv时，如果返回0，则表示对端关闭；返回负数，表示出错
				rt_printf_time ("104客户端关闭(net=%d,ret=%d)\r\n",net,len);
				msleep(100);
				break;
			}
			else
			{
				rt_fifo_put(&g_net_104_fifo[net],g_net_104_buf_frame[net],len);
				recv_timeout=dTCounter; 	//超时计数器清零
				if(tRunPara.tNetPara[net].ethid<CFG_ETH_NUM_MAX)
					g_run_stu.led[CFG_UART_NUM_MAX*2+tRunPara.tNetPara[net].ethid]=1;				
			}
			
			// 接收数据
			while(g_t104[net].bSM2Data== false && g_t104[net].bRecvOk == false)
			{
				if(rt_fifo_get(&g_net_104_fifo[net],&buf,1))
				{
					IEC104_Recv(&g_t104[net],buf);
				}
				else
				{
					break;
				}
			}
		}

		// 关闭客户端socket
		g_104_client[net] = RT_SOCKET_ERR;
		rt_socket_close (s);
	//	rt_printf_time ("net_104link_thread:rt_recv(ret=%d)\r\n",len);
	}

	// 理论上，程序不会运行到这儿
	return 0;
}



#endif


/*------------------------------ 测试函数 -------------------------------------
一个实体文件必须带一个本模块的测试函数来进行单元测试，如果的确不方便在本模块中
进行单元测试，必须在此注明实际的测试位置（例如在哪个实体文件中使用哪个测试函数）.
*/


/*------------------------------ 文件结束 -------------------------------------
*/
