/********************************************************************
版权所有：	
文件版本： V1.00
文件名称： IEC_LINK.c
生成日期： 2010年04月26日
作    者：hhw
使用范围：

功    能： 装置级联处理
更新信息：
更新日志1
修改者:
修改日期:
修改内容:
修改原因:
*********************************************************************/
#include    "head.h"  

volatile int 	g_net_104link_data[CFG_LINK_104_NUM];

// 级联104初始化标志
int g_link104_init_ok[CFG_LINK_104_NUM];

u8 g_link104_buf[CFG_LINK_104_NUM][IEC_BUF_LEN];
IECLINK_DEF g_link_104[CFG_LINK_104_NUM];


LINKYK_DEF g_lnk_yk[SWITCH_NUM_EXT_PUB];
LINKPAR_DEF g_link_par[SWITCH_NUM_EXT_PUB];
u8   g_link_par_cnt=0;      /*当前遥参游标*/

#ifdef IEC_NOLINK_NO_CALLYX
IEC_LINK_REG g_link_comm;
#endif


int get_index_setno(u8 	group_type,u16 setno)
{
	int i=0;
	for(i=0;i<ParaIDNum;i++)
	{
		if(tParaID[i].link_ch != 0)	continue;		//不是本地定值
		
		if((tParaID[i].group_type == group_type) && (tParaID[i].setno == setno))
		{
			return i;
		}
	}
	
	return -1;
}

#ifdef YPARA_LINK

msg_data_struct temp_par;

void print_msg_base(msg_ypara_data_struct *msg)
{
	int i=0;

	for(i=0;i<msg->num;i++)
	{
		rt_printf("%02d:cp_m[%x],cp_s[%x],len=%d\r\n",i,msg->base_data[i].cp_m,msg->base_data[i].cp_s,msg->base_data[i].val_iec.size);
				
	}
}


par_queque_m * lnk_msg_ypara_head_s(u8 chnl)
{	
	u8 ch=0;
	u8 index=0;

	ch=(chnl>>5)&0x07;
	index = chnl&0x1f;

	if(ch >= 2)		/*串口*/
	{
		ch -= 2;		/*串口号*/
		if((ch < CFG_UART_NUM_MAX) && (tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_M))
		{
			IECLINK_DEF *pt;
			pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf;	
			return &pt->par_queue;
		}	
#ifdef FUN_IEC103_STA
		else if((ch < CFG_UART_NUM_MAX) && 
			(tRunPara.tUartPara[ch].wProtocol == PROTOCOL_103_M || tRunPara.tUartPara[ch].wProtocol == PROTOCOL_YZ103_M))
		{
			IECLINK_DEF *pt;
			pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf;	
			return &pt->par_queue;
		}
#endif
	}
	else		/*网口*/
	{
		index = index - 1;			/*级联网络号*/
		// 以太网通道
		if(index < CFG_LINK_104_NUM)
		{
			IECLINK_DEF *pt;
			pt=&g_link_104[index];

			if(g_link104_init_ok[index] == 0)
			{
				return 0;
			}
			else
			{
				return &pt->par_queue;
			}
		}		
	}
		
	return 0;
}

msg_data_struct * lnk_msg_ypara_head_m(u8 chnl)
{	
	u8 ch=0;

	ch = chnl;
	if(ch < CFG_UART_NUM_MAX)	/*串口子站*/
	{		
		IEC101_DEF *pt101;	
		pt101 = (IEC101_DEF *)g_tRsComm[ch].ptBuf;
		
		if((tRunPara.tUartPara[ch].wProtocol==PROTOCOL_101) 
			|| (tRunPara.tUartPara[ch].wProtocol==PROTOCOL_101_PH))  // 串口级联规约
		{
			return &pt101->msg_ypara_recv;			
		}								
	}
	else if(ch < CFG_UART_NUM_MAX + CFG_ETH_MAX_LOGIC)	/*网口104*/
	{		
		IEC104_DEF *pt104;	
		ch = chnl-CFG_UART_NUM_MAX;
		pt104=&g_t104[ch];
		
		return &pt104->msg_ypara_recv;
	}

	return 0;
}


int get_stbl_index_s(u16 parId)
{
	int i=0;
	for(i=0;i<ParaIDNum;i++)
	{
		if(tParaID[i].parId == parId) 
		{
			return i;
		}

	}

	return -1;
}

int get_index_link(u16 link_ch,u16 link_cp)
{
	int i=0;
	for(i=0;i<ParaIDNum;i++)
	{	
		if(tParaID[i].link_ch == 0)	continue;		//不是级联定值
		if(((tParaID[i].link_ch == link_ch) || ((tParaID[i].link_ch &0x1f) == 0x1F))
			&& (tParaID[i].link_cp == link_cp))
		{
			return i;
		}

	}

	return -1;
}

int mananger_msg_ypara_s(msg_data_struct *msg,u8 sport,u8 dport)
{
	int i=0;
	IECLINK_DEF *pt;
	par_queque_m	*par_queque;
	

	temp_par= *msg;
	
	if((dport & 0x1F) == 0x1F)		/*广播*/
	{		
		rt_printf("广播:::::::子站--->级联主站(msg),sport=%x,dport=%x,type=%d\r\n",sport,dport,msg->type);
		{
			for(i=0;i<CFG_LINK_104_NUM;i++)
			{	
				if(g_link104_init_ok[i] == 0)	continue;	//没初始化的不增加
				
				pt = &g_link_104[i]; 
				par_queque = &pt->par_queue;				

				temp_par.dport = msg->dport;
				temp_par.sport = 0x1F;		/*级联源口号0x1F表示不用返回*/
				temp_par.flag = 0x81;

				add_data_queque(&par_queque->queue,(u8 *)&temp_par,OVER_QUEUE);
															
			}							
			return 0;	
		}						
	}
	else
	{		
		rt_printf("常规:::::::子站--->级联主站(msg),sport=%x,dport=%x,type=%d\r\n",sport,dport,msg->type);
		par_queque = lnk_msg_ypara_head_s(dport);		
	
		if(par_queque == 0)
		{
			//sprintf(buf,"级联遥参:未找到从设备通道(link_ch=%02x)",dport);	
			//log_str_time(LOG_OPERATE,buf,0,0);
			rt_printf("级联遥参:未找到从设备通道(link_ch=%02x)\r\n",dport);			
			return -1;
		}	
				
		//print_msg_base(msg);		
		temp_par.dport = msg->dport;
		temp_par.sport = msg->sport;
		temp_par.flag = 0x81;

		add_data_queque(&par_queque->queue,(u8 *)&temp_par,OVER_QUEUE);			
		rt_printf("----par_queue  num=%d\r\n",get_queue_count(&par_queque->queue));				
		return 0;	
	}		

	return -1;
}

int rec_msg_ypara_return(msg_data_struct *msg,u8 sport,u8 dport)
{	
	msg_data_struct *msg_ypara;	

	
	rt_printf("级联主站---子站(msg),sport=%d,dport=%d,type=%d\r\n",sport,dport,msg->ypara_msg.type);

	if((dport & 0x1F) == 0x1F)	/*广播的不返回*/
	{
		return 0;
	}
	

	msg_ypara = lnk_msg_ypara_head_m(dport);		
	
	if(msg_ypara == 0)
	{
		rt_printf("级联主站---子站(msg)通道失败\r\n");
		return -1;
	}		
	//print_msg_base(msg);
	*msg_ypara = *msg;	
	msg_ypara->flag = 1;
		
	return 0;
}

void lnk_slave_ypara_write(IECLINK_DEF *pt,u8 chnl,u8 vsq,u8 cot,u8 *ps,bool b104)
{
	int i =0;
	u8 num=0;
	u8 off=0;
	u8 len =0;
	u16 link_cp=0;
	u8 pdi=0;

	
	msg_data_struct *msg_data;
	msg_ypara_data_struct *msg;		
	iec_val_struct v;			

	num=(vsq&0x7f);

	msg_data = &pt->temp_par;
	msg = &pt->temp_par.ypara_msg;	
	memset(msg,0,sizeof(msg_ypara_data_struct));

	off += 2;	/*定值区*/
	pdi = ps[off++];		/*参数特征标识*/
	for(i=0;i<num;i++)
	{		
		link_cp=(ps[off]+(ps[off+1]<<8));
		
		off += 2;				
		if(b104) off +=1;	

		v.tag = ps[off++];
		v.size = ps[off++];
		memcpy(v.value,&ps[off],v.size);
		len = v.size+2;		
		off += v.size;
		
		msg->base_data[msg->num].val_iec = v;						
		msg->base_data[msg->num].cp_s  = link_cp;	
		msg->base_data[msg->num].cp_m  = 0;
		msg->num++;																					
	}
	
	if((pdi&0xc0)==0) // 定值固化
	{
		if(cot & IEC_COT_PN)
		{			
			msg->cmd = YP_EXE_FAULT;
		}
		else
		{
			msg->cmd = YP_EXE_RETURN;
		}		
	}	
	else if((pdi&0xc0)==0x40)	/*撤销*/
	{
		if(cot & IEC_COT_PN)
		{			
			msg->cmd = YP_CANCEL_FAULT;
		}
		else
		{
			msg->cmd = YP_CANCEL_RETURN;
		}
	}
	else  // 参数预置
	{
		if(cot & IEC_COT_PN)
		{			
			msg->cmd = YP_SEL_FAULT;
		}
		else
		{
			msg->cmd = YP_SEL_RETURN;
		}													
	}
	
	msg->type = modify_set; 
	msg_data->dport = pt->sport;
	msg_data->sport = chnl;
	
	rec_msg_ypara_return(msg_data,msg_data->sport,msg_data->dport);		
}

void lnk_slave_ypara_read(IECLINK_DEF *pt,u8 chnl,u8 vsq,u8 cot,u8 *ps,bool b104)
{
	int i =0;
	u8 num=0;
	u8 off=0;
	u16 link_cp=0;
	int index=0;
	SET_PARA_VAL *tmp_pval;
	u8 type=0,len=0;
	char str[64];

	num=(vsq&0x7f);
	
	off += 2;	/*定值区*/
	off++;		/*参数特征标识*/		
	
	if(cot & IEC_COT_PN)
	{			
		return ;		
	}

	
	for(i=0;i<num;i++)
	{		
		link_cp=(ps[off]+(ps[off+1]<<8));
		
		off += 2;				
		if(b104) off +=1;		

		type = ps[off++];
		len  = 	ps[off++];	
		if(len <sizeof(str))
		{
			memcpy(str,&ps[off],len);				
			off += len;
			
			index = get_index_link(chnl,link_cp);
			if(index < 0)
			{			
				//rt_printf("M104_read_unpack::index<0,chnl=0x%x,di=0x%x\r\n",chnl,link_cp);
				continue;
			}
					
			tmp_pval = &tPara_val[index];
			tmp_pval->datatype = type;
			tmp_pval->len  = 	len;		
			memcpy(tmp_pval->str,str,len);		
			//rt_printf("M104_read_unpack::chnl=0x%x,di=0x%x,tmp_pval[%d]:datatype=0x%x,len=0x%x\r\n",chnl,link_cp,index,tmp_pval->datatype,tmp_pval->len);	
		}
		else
		{
			off += len;								
		}																												
	}		
	
}



void lnk_slave_ypara_updata(IECLINK_DEF *pt,u8 *ps)
{
	u8 flag=0;
	
	ps += 3;	/*信息体地址*/
	flag = ps[0];

	if(flag)
	{
		set_read_all(pt);
	}

}

void set_read_all(IECLINK_DEF *pt)
{	
	LNK_STATUS *ptlnk = &pt->tlnk;
	
	//rt_printf("!!!!!!!![%d]----set\r\n,",pt->chnl);
	ptlnk->bSet_all=true;	
}

void clear_read_all(IECLINK_DEF *pt)
{	
	LNK_STATUS *ptlnk = &pt->tlnk;
	
	//rt_printf("!!!!!!!![%d]----clear\r\n,",pt->chnl);
	ptlnk->bSet_all=false;	
}

void print_tPara_val(int index)
{
	SET_PARA_VAL	*tmp_pval;
	float val=0;
	if(index >=MAX_SET_NUMBER)	return;
	
	tmp_pval = &tPara_val[index];
	switch(tmp_pval->datatype)
	{
		case BOOL_R:
		case TINY_R:
		case UTINY_R:		
			val=tmp_pval->str[0];
			rt_printf("-----val[%f-[%02x]]\r\n",val,tmp_pval->str[0]);
			break;		
		case UINT_R:
		case INT_R:
		case LONG_R:
		case ULONG_R:
			val=(tmp_pval->str[0]+(tmp_pval->str[1]<<8)+(tmp_pval->str[2]<<16)+(tmp_pval->str[3]<<24));
			rt_printf("-----val[%f-[%02x-%02x-%02x-%02x]]\r\n",val,tmp_pval->str[0],tmp_pval->str[1],tmp_pval->str[2],tmp_pval->str[3]);
			break;
		case SHORT_R:
		case USHORT_R:
			val=(tmp_pval->str[0]+(tmp_pval->str[1]<<8));		
			rt_printf("-----val[%f-[%02x-%02x]]\r\n",val,tmp_pval->str[0],tmp_pval->str[1]);
			break;		
		case FLOAT_R:
			{
				union{
					float ff;
					u8 tt[4];
					}ff;	

				ff.tt[3]=tmp_pval->str[0];
				ff.tt[2]=tmp_pval->str[1];
				ff.tt[1]=tmp_pval->str[2];
				ff.tt[0]=tmp_pval->str[3];
				val=ff.ff;		
				rt_printf("-----val[%f-[%02x-%02x-%02x-%02x]]\r\n",val,tmp_pval->str[0],tmp_pval->str[1],tmp_pval->str[2],tmp_pval->str[3]);
				break;	
			}																																	
	}	
}

#endif


u32 * lnk_get_ch_par_head(u8 chnl)
{
	u8 ch=chnl;
	u8 index=0;
	
	ch=(chnl>>5)&0x07;	
	index = chnl&0x1f;
	
	if(ch>=2) // 串口
	{
		ch -=2;
		if(ch < CFG_LINK_101_NUM &&( tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_PH_M))
		{
			IECLINK_DEF *pt;
			pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf;
			return &pt->par_send_flag;
		}	
	}
	else		/*网口*/
	{
		index = index - 1;			/*级联网络号*/
		// 以太网通道
		if(index < CFG_LINK_104_NUM)
		{
			IECLINK_DEF *pt;
			pt=&g_link_104[index];

			return &pt->par_send_flag;		
		}		
	}
	return 0;
}

u32 * lnk_get_ch_head(u8 chnl)
{
	u8 ch=chnl;
	ch=(chnl>>5)&0x07;
	if(ch>=2) // 串口
	{
		ch -=2;
		if(ch < CFG_LINK_101_NUM &&( tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_PH_M))
		{
			IECLINK_DEF *pt;
			pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf;
			return &pt->yk_send_flag;
		}	

		else if(ch < CFG_LINK_101_NUM && tRunPara.tUartPara[ch].wProtocol == PROTOCOL_MODBUS)
		{
			MODBUS_DEF *pt;
			pt= (MODBUS_DEF *)g_tRsComm[ch].ptBuf;
			return &pt->yk_send_flag;
		}
	#if defined BATTERY_WITH_COMM && defined FUNC_SEL_BAT_MODULE
		else if(ch < CFG_LINK_101_NUM && tRunPara.tUartPara[ch].wProtocol == PROTOCOL_PWRM)
		{
			pwdmodlue_def *pt;
			pt= (pwdmodlue_def *)g_tRsComm[ch].ptBuf;
			return &pt->yk_sendflag;						
		}
	#endif
	}
	else // 网口
	{
		ch=chnl-1;
		// 以太网通道
		if(ch < CFG_LINK_104_NUM)
		{
			IECLINK_DEF *pt;
			pt=&g_link_104[ch];
			return &pt->yk_send_flag;
		}
	}

	return 0;
}


void lnk_call_all(void)
{
	int	i;

	for(i=0; i<CFG_LINK_104_NUM; i++)
	{
		g_link_104[i].tlnk.bCallAll = true;
	}

	for(i=0; i<CFG_LINK_101_NUM; i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_PH_M)
		{

			int j;
			IECLINK_DEF *pt=(IECLINK_DEF *)g_tRsComm[i].ptBuf;
			if(pt == NULL)
				continue;
			for(j=0;j<pt->slave_num;j++)
			{
				pt->tsla[j].tlnksave.bCallAll=true;
			}	
			pt->tlnk.bCallAll=true;
		}
	}
}

void lnk_rst_set(void)
{
	int	i;

	for(i=0; i<CFG_LINK_104_NUM; i++)
	{
		g_link_104[i].tlnk.brst = true;
	}

	for(i=0; i<CFG_LINK_101_NUM; i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_PH_M)
		{
			int j;
			IECLINK_DEF *pt=(IECLINK_DEF *)g_tRsComm[i].ptBuf;
			if(pt == NULL)
				continue;
			pt->tlnk.brst=true;
			for(j=0;j<pt->slave_num;j++)
			{
				pt->tsla[j].tlnksave.brst=true;
			}			
		}
	}
}


void lnk_update_time_all(void)
{
	int	i;

	for(i=0; i<CFG_LINK_104_NUM; i++)
	{
		g_link_104[i].tlnk.bSetTime = true;
	}

	for(i=0; i<CFG_LINK_101_NUM; i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_PH_M)
		{
			int j;
			IECLINK_DEF *pt=(IECLINK_DEF *)g_tRsComm[i].ptBuf;
			if(pt == NULL)
				continue;
			for(j=0;j<pt->slave_num;j++)
			{
				pt->tsla[j].tlnksave.bSetTime=true;
			}
			pt->tlnk.bSetTime = true;
		}
	}
}


void lnk_slave_yx(u8 ch,u8 ti,u8 vsq,u8 cot,u8 al,u8 *ps)
{
	u8 num=(vsq&0x7f);
	u8 ngd=(vsq&0x80);
	u8 v;
	u16 cp;
	int i;					
	LINK_TABLE * lt;
	//struct di_table *dt;

	// 获取首地址
	cp =(ps[0]+(ps[1]<<8));					
	ps+=al;
	
	// 循环处理每个数据
	for(i=0;i<num;i++)
	{
		// 获取值，如果是单点，转化为双点保存
		v=*ps++;
		if(ti==1)
		{
			v+=1;  
		}

		// 查找点表，如果找到，保存。
		lt = tbl_link_di(ch,cp);

		if(lt)
		{
			sw_di_set(lt->owner,lt->indexno,v);
			
		}		
		// 根据ngd修正后续地址
		if(ngd)  
		{
			cp++;
		}
		else
		{
			cp=(ps[0]+(ps[1]<<8));	
			ps+=al;							
		}
	}	
}

void lnk_find_yx_iec_no(u8 ch, u8 *ps)// 寻找级联点号对应的点表中点号，并替换
{

	int i;
	u16 di;
	di=ps[0]+(ps[1]<<8);
	for(i=0;i<g_table_head->di_num;i++)
	{
		if(g_di_table[i].link_ch!=0)
		{
			if((g_di_table[i].link_cp==di) && (g_di_table[i].link_ch == ch))  // 级联点号有对应的点表值
			{
				ps[0]=(u8)g_di_table[i].cp;
				ps[1]=(u8)(g_di_table[i].cp>>8);
				//rt_printf("\r\n yx %04x-->%04x",g_di_table[i].cp,di);
				break;
			}
		}
	}
}

void lnk_find_yc_iec_no(u8 ch, u8 *ps,u8 baddr3,u8 yc_type)// 寻找级联点号对应的点表中点号，并替换
{
	int i;
	u16 di;	
	
	di=ps[0]+(ps[1]<<8);
	for(i=0;i<g_table_head->ac_num;i++)
	{
		if(g_ac_table[i].link_ch!=0)
		{
			if((g_ac_table[i].link_cp==di) && (g_ac_table[i].link_ch == ch))  // 级联点号有对应的点表值
			{
				ps[0]=(u8)g_ac_table[i].cp;
				ps[1]=(u8)(g_ac_table[i].cp>>8);
								
				if(pRunSet->bTT_EV_YCRate)
				{
					union{
						float ff;
						u8 tt[4];
					}ff;	
					u8 *pdat;					
					u16 v=0;
					
					pdat = &ps[2];
					if(baddr3)	pdat =	&ps[3];
					
					if(yc_type == 13)
					{
						#ifdef MODE_LITTLE_ENDIAN
							ff.tt[0]=pdat[0];
							ff.tt[1]=pdat[1];
							ff.tt[2]=pdat[2];
							ff.tt[3]=pdat[3];
						#else	
							ff.tt[3]=pdat[0];
							ff.tt[2]=pdat[1];
							ff.tt[1]=pdat[2];
							ff.tt[0]=pdat[3];
						#endif					
					}
					else
					{
						ff.ff = pdat[0] + (pdat[1]<<8);
					}
					rt_printf("fault_yc_two::%f\r\n",ff.ff);				
					ff.ff *= ((float)g_ac_table[i].rate/65536.0); 	//系数转换	
					v = ff.ff;
					
					rt_printf("fault_yc_one::%f\r\n",ff.ff);

					if(yc_type == 13)
					{
						#ifdef MODE_LITTLE_ENDIAN
							pdat[0] = ff.tt[0];
							pdat[1] = ff.tt[1];
							pdat[2] = ff.tt[2];
							pdat[3] = ff.tt[3];
						#else	
							pdat[0] = ff.tt[3];
							pdat[1] = ff.tt[2];
							pdat[2] = ff.tt[1];
							pdat[3] = ff.tt[0];
						#endif					
					}
					else
					{
						pdat[0] = (u8)v;					
						pdat[1] = (u8)(v>>8);
					}															
				}						
				//rt_printf("\r\n yc %04x-->%04x",g_ac_table[i].cp,di);
				break;
			}
		}
	}
}


int EventInfoAddr101_to_104(BYTE *frame,BYTE *pbuf)
{
	int len;
	int yc_num,yc_type;
	int i,buf_pos=0,frame_pos=0;

	memcpy(pbuf,frame,4);
	buf_pos += 4;
	frame_pos += 4;	
	memcpy(&pbuf[buf_pos],&frame[frame_pos],8);

	
	buf_pos += 8;
	frame_pos += 8;
	yc_num = frame[frame_pos];
	yc_type = frame[frame_pos+1];	
	memcpy(&pbuf[buf_pos],&frame[frame_pos],2);
	buf_pos += 2;
	frame_pos += 2;
	for(i=0;i<yc_num;i++){
		memcpy(&pbuf[buf_pos],&frame[frame_pos],2);
		buf_pos += 2;
		frame_pos += 2;	
	
		pbuf[buf_pos++] = 0;	//信息体地址
		
		if(yc_type == 0x0D){
			len = 4;
		}else{
			len = 2;
		}
		memcpy(&pbuf[buf_pos],&frame[frame_pos],len);
		buf_pos += len;
		frame_pos += len;
	}

	return buf_pos;
}


int EventInfoAddr104_to_101(BYTE *frame,BYTE *pbuf)
{
	int len;
	int yc_num,yc_type;
	int i,buf_pos=0,frame_pos=0;

	memcpy(pbuf,frame,4);
	buf_pos += 4;
	frame_pos += 4;	
	memcpy(&pbuf[buf_pos],&frame[frame_pos],8);

	
	buf_pos += 8;
	frame_pos += 8;
	yc_num = frame[frame_pos];
	yc_type = frame[frame_pos+1];	
	memcpy(&pbuf[buf_pos],&frame[frame_pos],2);
	buf_pos += 2;
	frame_pos += 2;
	for(i=0;i<yc_num;i++){
		memcpy(&pbuf[buf_pos],&frame[frame_pos],2);
		buf_pos += 2;
		frame_pos += 2;
		
		frame_pos++;	//信息体地址
		
		if(yc_type == 0x0D){
			len = 4;
		}else{
			len = 2;
		}
		memcpy(&pbuf[buf_pos],&frame[frame_pos],len);
		buf_pos += len;
		frame_pos += len;
	}

	return buf_pos;
}


void lnk_slave_fault(u8 ch,u8 len,u8 *ps, bool b104)
{
	int i;
	int num;
	u8 yctype;
	u8 *pdat;
	int frame_len;
	BYTE tmp_buf[256];
	
	pdat=ps;
	if(len>=IEC_FAULT_FRAMELEN-1)return;

	num=pdat[0];
	pdat+=2;
	for(i=0;i<num;i++)  // ps[0] 遥信个数
	{
		lnk_find_yx_iec_no(ch, &pdat[0]);
		pdat+=10;
	}
	num=pdat[0];
	yctype=pdat[1];
	pdat+=2;
	for(i=0;i<num;i++)  // ps[0] 遥测个数
	{
		lnk_find_yc_iec_no(ch, &pdat[0],b104,yctype);

		if(b104)
		{
			if(yctype==13)  //浮点值四个字节
			{
				pdat+=7;
			}
			else
			{
				pdat+=5;
			}
		}
		else
		{
			if(yctype==13)  //浮点值四个字节
			{
				pdat+=6;
			}
			else
			{
				pdat+=4;
			}
		}
	}
	
	for(i=0;i<CFG_UART_NUM_MAX;i++)
	{
		if(tRunPara.tUartPara[i].wProtocol==PROTOCOL_101||tRunPara.tUartPara[i].wProtocol==PROTOCOL_101_PH) //子站规约
		{
			IEC101_DEF *pt=(IEC101_DEF *)g_tRsComm[i].ptBuf;
			
			if(b104)	
			{
				frame_len = EventInfoAddr104_to_101(ps,tmp_buf);				
				if(frame_len > IEC_FAULT_FRAMELEN-1)	continue;	
				memcpy(&pt->tfault.data[pt->tfault.head][1],tmp_buf,frame_len);	
				pt->tfault.data[pt->tfault.head][0]=frame_len;			
			}
			else
			{
				memcpy(&pt->tfault.data[pt->tfault.head][1],ps,len);	
				pt->tfault.data[pt->tfault.head][0]=len;	
			}								
			pt->tfault.head++;			
			if(pt->tfault.head==pt->tfault.tail)
			{
				pt->tfault.tail++;
			}			
		}
	}
	for(i=0;i<CFG_ETH_MAX_LOGIC;i++)
	{
		IEC104_DEF *pt;
		pt=&g_t104[i];	
		if(b104 == false)
		{
			frame_len = EventInfoAddr101_to_104(ps,tmp_buf);			
			if(frame_len > IEC_FAULT_FRAMELEN-1)	continue;
			memcpy(&pt->tfault.data[pt->tfault.head][1],tmp_buf,frame_len);	
			pt->tfault.data[pt->tfault.head][0]=frame_len;	

		}
		else
		{
			memcpy(&pt->tfault.data[pt->tfault.head][1],ps,len);	
			pt->tfault.data[pt->tfault.head][0]=len;	
		}			
		rt_printf("\r\n fault lenth=%d head=%d",len,pt->tfault.head);
		pt->tfault.head++;
		if(pt->tfault.head==pt->tfault.tail)
		{
			pt->tfault.tail++;
		}		
	}

}



// 
void lnk_slave_yc(u8 ch,u8 ti,u8 vsq,u8 al,u8 *ps)
{
	u8 num=(vsq&0x7f);
	u8 ngd=(vsq&0x80);
	u16 cp;
	int i;					
	LINK_TABLE * lt;
	struct ac_table *at;
	u8 ycQDS=0;
	qs16 v;
#ifndef MODE_LITTLE_ENDIAN
	u8 ycval[4];
#endif

	// 获取首地址
	cp=(ps[0]+(ps[1]<<8));			
	ps+=al;

	// 循环处理每个数据
	for(i=0;i<num;i++)
	{
		// 根据类型，将遥测转换为qs16格式的值。
		if(ti==13)  
		{
			// 浮点
#ifdef MODE_LITTLE_ENDIAN
			union
			{
				u8 arr[4];
				float fval;
			}tmpyc;

			tmpyc.arr[0] = *ps++;
			tmpyc.arr[1] = *ps++;
			tmpyc.arr[2] = *ps++;
			tmpyc.arr[3] = *ps++;

			v = (qs16)(tmpyc.fval*Q16_BASE);

#else
			ycval[3]=*ps++;
			ycval[2]=*ps++;
			ycval[1]=*ps++;
			ycval[0]=*ps++;			
			v = *(float *)ycval*Q16_BASE;

#endif

		}
		else
		{
			//归一、标度
			v = (ps[0]<<16) | (ps[1]<<24);
			ps += 2;
		}

		// TODO:记录QDS，需后续处理
		if(ti != 21)
		{
			ycQDS=*ps++;
		}

		// 记录遥测值
		// rt_printf_time("ch=%d,cp=%04x,v=%s.\r\n",ch,cp,q16_to_str(v));
		lt = tbl_link_ac(ch,cp);
		if(lt)
		{
			
			at = &g_ac_table[lt->tbl_index];
			if(at->owner == 0)
			{
				g_sw_pub.ac_in[at->indexno-1] = v;
			}
			else
			{
				g_sw[at->owner-1].ac_in[at->indexno-1] = v;
				g_sw[at->owner-1].link_qds[at->indexno-1] = ycQDS;

			}
		}


		// 根据ngd修正后续地址
		if(ngd)  
		{
			cp++;
		}
		else
		{
			cp=(ps[0]+(ps[1]<<8));	
			ps+=al;							
		}
	}
}


// 
void lnk_slave_dd(u8 ch,u8 ti,u8 vsq,u8 cot,u8 al,u8 *ps)
{
	u8 num=(vsq&0x7f);
	u8 ngd=(vsq&0x80);
	u16 cp;
	int i;					
	LINK_TABLE * lt;
	struct dd_table *dt;
	struct rtc_time_t  ct;

	u8 QDS;
	bool bchange=false;
	float v;
#ifndef MODE_LITTLE_ENDIAN
		u8 ycval[4];
#endif

	// 获取首地址
	cp=(ps[0]+(ps[1]<<8));			
	ps+=al;

	// 循环处理每个数据
	for(i=0;i<num;i++)
	{

#ifdef MODE_LITTLE_ENDIAN
		union
		{
			u8 arr[4];
			float fval;
		}tmpyc;

		tmpyc.arr[0] = *ps++;
		tmpyc.arr[1] = *ps++;
		tmpyc.arr[2] = *ps++;
		tmpyc.arr[3] = *ps++;

		v = tmpyc.fval;

#else
		ycval[3]=*ps++;
		ycval[2]=*ps++;
		ycval[1]=*ps++;
		ycval[0]=*ps++;
		v = *(float *)ycval;
#endif

		QDS=*ps++;
		if(ti==207) // 带时标电度
		{
			ct.ms=ps[0]+(ps[1]<<8);
			ct.min=ps[2];
			ct.hour=ps[3];
			ct.day=ps[4];
			ct.month=ps[5];
			ct.year=ps[6];
			ps+=7;
			if(cot==3)  //突发上送
			{
				bchange=true;
			}
		}
		else
		{
			ct.ms=0;
			ct.ms=0;
			ct.min=0;
			ct.hour=0;
			ct.day=0;
			ct.month=0;
			ct.year=0;
			bchange=false;
		}

		// 记录遥测值
		// rt_printf_time("ch=%d,cp=%04x,v=%.4f.\r\n",ch,cp,v);
		lt = tbl_link_dd(ch,cp);
		if(lt)
		{
			dt = &g_dd_table[lt->tbl_index];
			if((dt->owner >0)&&(pRunSet->dd_calc_mode == 2))
			{
			
#ifdef M_IT_TC
				int j=0;
											
				if(bchange)//级联突发上送
				{
					for(j=0;j<CFG_UART_NUM_MAX;j++)
					{
						g_sw[dt->owner-1].dd[dt->indexno-1].bsend101[j] = true;
					}

					for(j=0;j<CFG_ETH_MAX_LOGIC;j++)
					{
						g_sw[dt->owner-1].dd[dt->indexno-1].bsend104[j] = true;
					}
				}
#endif
				g_sw[dt->owner-1].dd[dt->indexno-1].fv= v;
				g_sw[dt->owner-1].dd[dt->indexno-1].ct= ct;
				g_sw[dt->owner-1].dd[dt->indexno-1].bchanged= bchange;


				// 记录遥测值
				 //rt_printf_time("owner=%d,index=%04x,v=%.4f.\r\n",dt->owner-1,dt->indexno,v);
			}
		}
		// 根据ngd修正后续地址
		if(ngd)  
		{
			cp++;
		}
		else
		{
			cp=(ps[0]+(ps[1]<<8));	
			ps+=al;							
		}
	}
}

void lnk_slave_soe(IECLINK_DEF *pt,u8 ch,u8 ti,u8 vsq,u8 al,u8 *ps)
{
	u8 num=(vsq&0x7f);
	u8 ngd=(vsq&0x80);
	u8 v;
	u16 cp;
	int i;					
	LINK_TABLE * lt;
//	struct di_table *dt;
	
	struct rtc_time_t rt;
	struct timespec ts;
	
	// 获取首地址
	cp=(ps[0]+(ps[1]<<8));			
	ps+=al;

	// 循环处理每个数据
	for(i=0;i<num;i++)
	{
		// 获取值，如果是单点，转化为双点保存
		v=*ps++;
		if(ti==30)
		{
			v+=1;  
		}
		
		// 获取时间
		rt.ms	= *ps++;
		rt.ms  |= (*ps++)<<8;
		rt.min	= *ps++;
		rt.hour = *ps++;
		rt.day	= ((*ps++)&0x1f);
		rt.month= *ps++;
		rt.year	= *ps++;	
#ifdef  FUN_YPARA_CFG_NOTY	
		if(cp == 0x8001)		/*参数变化,特殊soe*/
		{			
			if(v == 2)
			{			
				set_read_all(pt);
				if(soe_check(EV_PARA_CHG)==false)   // 
				{
					soe_record_ev(EV_PARA_CHG, 1, 0,0,0 );
				}		
				dTpartime =  ustimer_get_origin();
			}						
		}
#endif

		// 查找点表，如果找到，保存。
		lt = tbl_link_di(ch,cp);
		if(lt)
		{
			//dt = &g_di_table[lt->tbl_index];
			sw_di_set(lt->owner,lt->indexno,v);
			
			rtc_to_timespec(&rt,&ts);
			v = lt->is_inverse ? ((~v)&0x03) : v;
			soe_record_lnk(lt->cp ,v,&ts,(s32)lt,lt->is_mix,lt->cp_s);
		}		
		// 根据ngd修正后续地址
		if(ngd)  
		{
			cp++;
		}
		else
		{
			cp=(ps[0]+(ps[1]<<8));	
			ps+=al;							
		}
	}
}
extern u8 get_par_link_data(BYTE *out,BYTE *in,BYTE parNum,u8 ti);//test
void lnk_slave_par(u8 ch,u8 ti,u8 cot,u8 al,u8 *ps,u8 vsq)
{
	u8 ti_m=ti;
	u8 v,yktype;
	u16 cp;
	LINK_TABLE * lt;
	//struct do_table *dt;
	LINKPAR_DEF *par;
	u8 *pbuf=ps;
	int i;
	// 获取地址和值
	cp=(ps[0]+(ps[1]<<8));			
	ps+=al;
	v=*ps++;
		
	// 查找点表，如果找到，保存。
	lt = tbl_link_do(ch,cp);
	lt = &g_lt_do[1];

#ifdef YC_QUANTITY
	rt_printf("\r\nch=%02x parAddr=%02x vsq=%d\r\n",(ch>>4),cp-(pRunSet->dYC_num*((ch&0x0f)-1)),vsq);
	cp=cp-(pRunSet->dYC_num*((ch&0x0f)-1)) ;//点表转换
#else
	rt_printf("\r\nch=%02x parAddr=%02x vsq=%d\r\n",(ch>>4),cp-(FOS_PAR_SW_NUM*((ch&0x0f)-1)),vsq);
	cp=cp-(FOS_PAR_SW_NUM*((ch&0x0f)-1)) ;//点表转换
#endif

	for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
	{	
	#ifdef FUNC_MORE_PREREAD
		if(g_link_par[i].flag[IECLINK_YK_SND] == false) continue;	
	#endif		
	
		//if((g_link_par[i].cp_s == cp||g_link_par[i].cp_s ==(pbuf[0]+(pbuf[1]<<8)) )&& g_link_par[i].data[IECLINK_YK_SND].ti==0xff)//当前sw归属对应点号有效
		if((g_link_par[i].cp_s ==(pbuf[0]+(pbuf[1]<<8)) )&& g_link_par[i].data[IECLINK_YK_SND].ti==0xff)//当前sw归属对应点号有效
		{					
			par = &g_link_par[i];
			rt_printf("\r\n i=%x  Ti=%02x ti_m=%02x  cp_s%02x cp_m %02x  chnl=%02x \r\n",i,g_link_par[i].data[IECLINK_YK_SND].ti,g_link_par[i].data[IECLINK_YK_SND].ti_m,g_link_par[i].cp_m,g_link_par[i].cp_s,g_link_par[i].cp_m,g_link_par[i].chnl);		
			#if 0// 由于有些从设备只发10，不发07，所以在10时将 07 10 报文同时发出。
			if(cot == 10 && (par->data[IECLINK_YK_ACK].ti == 0))
			{
				yktype = IECLINK_YK_ACK;

				par->data[yktype].ti=ti;
				par->data[yktype].cot=7;
				par->data[yktype].len=v;
				
				par->flag[yktype] = true;
			}
			#endif

			yktype = cot==10 ? IECLINK_YK_END : IECLINK_YK_ACK;

			if(ti == FOS_PAR_SET_MUL_EXT)
			{
				ti_m = FOS_PAR_SET_MUL;
			}
			else if(ti == FOS_PAR_SET_ONE_EXT)
			{
				ti_m = FOS_PAR_SET_ONE;
			}
			else if(ti == FOS_PAR_READ_ONE_EXT)
			{
				ti_m = FOS_PAR_READ_ONE;
			}
			else if(ti == FOS_PAR_READ_MUL_EXT)
			{
				ti_m = FOS_PAR_READ_MUL;
			}	
				
			par->data[yktype].ti=ti_m;
			par->data[yktype].cot=cot;
			par->data[yktype].len=1;
			par->data[yktype].vsq=vsq;
			//
			if(al == 2)
			{
				par->data[yktype].len = get_par_link_data(&par->data[yktype].buf[0] ,pbuf,vsq, ti_m);
			}
			else
			{
				par->data[yktype].len = get_par_link_data_dz(&par->data[yktype].buf[0] ,pbuf,vsq, ti_m);
			}
			par->flag[yktype] = true;
			
			rt_printf("级联遥参上行:(ch=%02x,cp_s=%04x,ti=%02x,cot=%02x,len=%02x yktype=%02x \r\n",ch,g_link_par[i].cp_s,ti_m,cot,par->data[yktype].len,yktype);
			
		#ifdef FUNC_MORE_PREREAD
			g_link_par[i].flag[IECLINK_YK_SND] = false;
		#endif
			return ;
		}
	}
	rt_printf_time("lnk_slave_par:查找级联表失败 ch=%02x,cp=%04x.\r\n",ch,cp);
	return ; 		
}


void lnk_slave_yk(u8 ch,u8 ti,u8 cot,u8 al,u8 *ps)
{
	u8 v,yktype;
	u16 cp;
	LINK_TABLE * lt;
	struct do_table *dt;
	LINKYK_DEF *yk;
	char buf[128];
	
	// 获取地址和值
	cp=(ps[0]+(ps[1]<<8));			
	ps+=al;
	v=*ps++;
		
	// 查找点表，如果找到，保存。
	lt = tbl_link_do(ch,cp);
	if(lt)
	{
		dt = &g_do_table[lt->tbl_index];
		yk = &g_lnk_yk[dt->owner];
		if(cp != yk->cp_s)
		{
			rt_printf_time("lnk_slave_yk err:cp=%04x,cp_s=%04x",cp,yk->cp_s);
			return;
		}

		// 由于有些从设备只发10，不发07，所以在10时将 07 10 报文同时发出。
		if(cot == 10 && (yk->data[IECLINK_YK_ACK].ti == 0))
		{
			yktype = IECLINK_YK_ACK;

			yk->data[yktype].ti=ti;
			yk->data[yktype].cot=7;
			yk->data[yktype].v=v;
			
			yk->flag[yktype] = true;
		}

		yktype = cot==10 ? IECLINK_YK_END : IECLINK_YK_ACK;

		yk->data[yktype].ti=ti;
		yk->data[yktype].cot=cot;
		yk->data[yktype].v=v;
		
		yk->flag[yktype] = true;
		
		sprintf(buf,"级联遥控上行:(ch=%02x,cp_s=%04x,cp_m=%04x,ti=%02x,cot=%02x,v=%02x)",ch,lt->cp_s,dt->cp,ti,cot,v);
		log_str_time(LOG_OPERATE,buf,0,0);
		rt_printf_time("%s\r\n",buf);

	}
	else
	{
		rt_printf_time("lnk_slave_yk:查找级联表失败 ch=%d,cp=%04x.\r\n",ch,cp);
	}
				
}

//定值参数&&... 数据级联转发
int lnk_master_par(struct do_table *pdt,u8 ti,u8 cot,u8 len,BYTE *datBuf,u8 vsq)
{
	u8 yktype;
	LINKPAR_DEF * par;
	char buf[128];
	u32 *par_send_flag;	

	// 获取对应通道的结构，获取失败，直接返回
	par_send_flag = lnk_get_ch_par_head(pdt->link_ch);
	if(par_send_flag == 0)
	{
		sprintf(buf,"级联:未找到从设备通道(cp=%04x,link_ch=%02x,link_cp=%04x)",pdt->cp,pdt->link_ch,pdt->link_cp);
		log_str_time(LOG_OPERATE,buf,0,0);
		rt_printf_time("%s\r\n",buf);
		return -1;
	}

	#ifdef FUNC_MORE_PREREAD
		  par = &g_link_par[g_link_par_cnt];
		  *par_send_flag |= 1<<g_link_par_cnt;	
	#else
		*par_send_flag |= (1<<pdt->owner);  
	 	 par = &g_link_par[pdt->owner];		
	#endif
		
	// 清对应数据结构
	memset(par,0,sizeof(g_link_par[0]));

	// 赋值
	yktype = IECLINK_YK_SND;
	
	par->data[yktype].ti=0xff;//???
	par->data[yktype].vsq=vsq;
	par->data[yktype].cot=cot;
	par->data[yktype].len=len;
	memcpy(par->data[yktype].buf,datBuf,len);
	
	par->cp_m=pdt->cp;				
	par->cp_s=pdt->link_cp;		
	par->chnl=pdt->link_ch;	
	
	par->flag[yktype] = true;

	//*par_send_flag |= (1<<pdt->owner);
	par->data[yktype].ti_m = ti;
	
	// 记录日志	
	sprintf(buf,"级联遥参下行:(cp=%04x,link_ch=%02x,link_cp=%04x,ti=%02x,cot=%02x,len=%02x ,ti_m=%02x)",pdt->cp,pdt->link_ch,pdt->link_cp,ti,cot,len,par->data[yktype].ti_m);
	log_str_time(LOG_OPERATE,buf,0,0);
	rt_printf_time("%s\r\n",buf);

	return 0;
}

int lnk_master_yk(struct do_table *pdt,u8 ti,u8 cot,u8 v)
{
	u8 yktype;
	LINKYK_DEF * yk;
	char buf[128];
	u32 *yk_send_flag;	

	// 获取对应通道的结构，获取失败，直接返回
	yk_send_flag = lnk_get_ch_head(pdt->link_ch);
	if(yk_send_flag == 0)
	{
		sprintf(buf,"级联遥控:未找到从设备通道(cp=%04x,link_ch=%02x,link_cp=%04x)",pdt->cp,pdt->link_ch,pdt->link_cp);
		log_str_time(LOG_OPERATE,buf,0,0);
		rt_printf_time("%s\r\n",buf);
		return -1;
	}

	yk = &g_lnk_yk[pdt->owner];

	// 清对应遥控数据结构
	memset(yk,0,sizeof(g_lnk_yk[0]));

	// 赋值
	yktype = IECLINK_YK_SND;
	
	yk->data[yktype].ti=ti;
	yk->data[yktype].cot=cot;
	yk->data[yktype].v=v;
	
	yk->cp_m=pdt->cp;				
	yk->cp_s=pdt->link_cp;		
	yk->chnl=pdt->link_ch;	
	
	yk->flag[yktype] = true;

	*yk_send_flag |= (1<<pdt->owner);

	// 记录日志
	sprintf(buf,"级联遥控下行:(cp=%04x,link_ch=%02x,link_cp=%04x,ti=%02x,cot=%02x,v=%02x)",pdt->cp,pdt->link_ch,pdt->link_cp,ti,cot,v);
	log_str_time(LOG_OPERATE,buf,0,0);
	rt_printf_time("%s\r\n",buf);


	return 0;
}
void lnk_count_slaveaddr(IECLINK_DEF *pt,u8 chnl,LINK_TABLE* lt,u32 num)
{
	u8 ch;
	u8 addr=0;
	int j;

	for(j=0;j<num;j++)	
	{
		ch=(u8)((lt->cp_s>>21)&0x0f);
		addr=(u8)((lt->cp_s>>16)&0x1f);

		if(addr>0&&(ch==chnl)) // 通道相符
		{
			if(pt->slave_num==0)
			{
				pt->tsla[pt->slave_num++].addr=addr;
			}
			else
			{
				int i;
				for(i=0;i<pt->slave_num;i++) // 查找子站地址是否保存
				{
					if(addr==pt->tsla[i].addr)
					{
						break;
					}
				}
				if(i==pt->slave_num)
				{
					pt->tsla[pt->slave_num++].addr=addr;
				}
				if(pt->slave_num>=32)pt->slave_num=31;
			}
		}
		lt++;
	}
}



int  getstrval(char *buf)
{
	char *str;
	int val=0;
	str=strchr(buf,'=');
	if(str)
	{
		str++;
		if(str[0]=='0'&&(str[1]=='x'||str[1]=='X'))
		{
			val=strtoul(str,NULL,16);
		}
		else
		{
			val=strtoul(str,NULL,10);
		}
	}
	return val;

}


static void lnk_getcfg(IECLINK_DEF *pt,u8 *filestr,u8 *keystr)
{
	u8 str[32],str1[32];
	if(filestr[0]=='[') // 是规约类型
	{
		pt->bcfg=false;
		sprintf(str,"[COM%d_%s]",pt->chnl,keystr);
		sprintf(str1,"[%s_ALL]",keystr);
		if(strcmp(filestr,str)==0||strcmp(filestr,str1)==0)
		{
			pt->bcfg=true;
		}
		return;
	}
	if(!pt->bcfg)return;
	if(strstr(filestr,"appaddr")) // 遥信命令码
	{
		pt->b101App2Byte=(getstrval(filestr)==2)?true:false;
	}
	else if(strstr(filestr,"linkaddr")) // 
	{
		pt->b101Addr2Byte=(getstrval(filestr)==2)?true:false;
	}
	else if(strstr(filestr,"cotaddr")) // 
	{
		pt->b101Cot2Byte=(getstrval(filestr)==2)?true:false;
	}
	else if(strstr(filestr,"callalltime")) // 
	{
		pt->callalltime=getstrval(filestr)*SAM_FREQUENCY;  // 单位秒，转为dTcounter 值
	}
	else if(strstr(filestr,"retrytime")) // 
	{
		pt->retrytime=getstrval(filestr)*SAM_FREQUENCY;  // 单位秒，转为dTcounter 值
	}
	else if(strstr(filestr,"sendinteraltime")) // 
	{
		pt->sendinteraltime=getstrval(filestr)*SAMFREQ/20; // 单位毫秒，转为dTcounter值
	}
	else if(strstr(filestr,"lb_master_en"))
	{
		pt->b_lb_master = getstrval(filestr);
	}
	else
	{
		return;
	}
}

static int  lnk_init_cfg(IECLINK_DEF *pt,u8 *keystr)
{
	u32 i,file_length;
	struct file * pfile;
	u8 *filebuf;
	u8  filestr[128],*pstr,strlenth;
	loff_t pos;
	// 打开文件


	pt->callalltime=SAM_FREQUENCY*15;
	pt->retrytime=SAM_FREQUENCY*5;
	pt->sendinteraltime=T_100ms;	

	rt_printf("\r\n%s:%d 级联参数初始化\r\n",keystr,pt->chnl);
	
	pfile = rt_file_open("/app/data/pcolcfg.ini",O_RDONLY ,0);
	if(IS_ERR(pfile))
	{
		dp_err_n_c_rt("\r\nerror! 无法打开 pcolcfg.ini\r\n");
		return -1;
	}

	// 得到文件长度
	file_length = rt_file_getfile_size(pfile);
	if(file_length <= 0)
	{
		rt_file_close(pfile,0);
		return -2; 	
	}

	// 分配内存
	filebuf = rt_malloc(file_length);
	if((filebuf) == NULL)
	{
		rt_file_close(pfile,0);
		return -3; 	
	}

	pos = 0;
	if(rt_file_read(pfile,filebuf,file_length,&pos) != file_length)
	{
		rt_file_close(pfile,0);
		rt_free(filebuf);
		return -4;
	}
	pstr = filestr;
	strlenth=0;   // 纠错处理
	//找到\r\n位置，得到一行长度
	for(i = 0; i < file_length; i++)
	{
		*pstr++=filebuf[i];
		strlenth++;
		if(filebuf[i] == 0x0a||strlenth>=128)
		{
			int j;
			pstr = filestr;
			for(j=0;j<strlenth;j++)
			{
				if(*pstr==' '||*pstr=='\t')  // 取空格或tab 前的字符
				{
					*pstr='\0';
					break;
				}
				pstr++;
			}
			*pstr='\0';
			lnk_getcfg(pt,filestr,keystr);
			pstr=filestr;
			strlenth=0;
		}
	}
	rt_file_close(pfile,0);	// 关闭文件
	rt_free(filebuf);			// 释放内存
	return 0;
}

void lnk_101_init(IECLINK_DEF *pt,u8 chnl,bool bPH)
{
	int i;
	LNK_STATUS *ptlnk=&pt->tlnk;
	memset(pt,0,sizeof(IECLINK_DEF));
	
	pt->type=IEC101_CHN;
	pt->chnl=chnl;
	pt->sendbuf=g_tRsComm[chnl].sendbuf;
	pt->bPH101=bPH;

	// 初始化状态
	ptlnk->bLinkOK=false;
	ptlnk->bCallLnk=true;
	
	ptlnk->dTMWait=dTCounter;
	ptlnk->dTInteral=dTCounter;
	ptlnk->dTCallAllTime=dTCounter;
	ptlnk->dTSendTime=dTCounter;

	pt->slave_num=0;
	pt->slave_current=0;

	lnk_init_cfg(pt,"IEC101_LNK");
	lnk_count_slaveaddr(pt,chnl+2,&g_lt_di[0],g_lt_di_num);
	lnk_count_slaveaddr(pt,chnl+2,&g_lt_ac[0],g_lt_ac_num);
	lnk_count_slaveaddr(pt,chnl+2,&g_lt_dd[0],g_lt_dd_num);
	lnk_count_slaveaddr(pt,chnl+2,&g_lt_do[0],g_lt_do_num);

	//rintf("port[%d]------101装置数量:%d\r\n",chnl,pt->slave_num);
#ifdef RCD_STRAN_M
	queue_init(&pt->rcd_m.queue,NEWRCD_COUNT_M,&pt->rcd_m.data,NEWRCD_SIZE_M);
#endif
#ifdef YPARA_LINK
	queue_init(&pt->par_queue.queue,PAR_COUNT_M,&pt->par_queue.data,PAR_SIZE_M);
	rt_printf("-----PAR_SIZE_M=%d\r\n",PAR_SIZE_M);
#endif

	// 判断 装置是否有电度
	for(i=0;i<pt->slave_num;i++)
	{  
		int j;
		pt->tsla[i].bDdValid=false;
		for(j=0;j<g_lt_dd_num;j++)
		{
			if(((WORD)((g_lt_dd[j].cp_s>>16)&0x1f))==pt->tsla[i].addr)
			{
				pt->tsla[i].bDdValid=true;
			}
		}
	}	

	for(i=0; i<pt->slave_num;i++)
	{
		// 初始化状态
		pt->tsla[i].tlnksave.bLinkOK=false;
		pt->tsla[i].tlnksave.bCallLnk=true;	

		pt->tsla[i].tlnksave.dTMWait=dTCounter;
		pt->tsla[i].tlnksave.dTInteral=dTCounter;
		pt->tsla[i].tlnksave.dTCallAllTime=dTCounter;
		pt->tsla[i].tlnksave.dTSendTime=dTCounter;
	}
		
	pt->slave_addr=pt->tsla[0].addr;
}

void lnk_101_send(IECLINK_DEF *pt)
{
	RS_Send_Enable(pt->chnl);
	g_tRsComm[pt->chnl].nSendCnt=1;   // 发送缓冲区的第一个字节为发送长度
	g_tRsComm[pt->chnl].bSend=true;
	if(g_print_lnk && (g_print_port & (1<<pt->chnl)))
	{
		char tmpstr[24];
		sprintf(tmpstr,"TL_101(%d):",pt->chnl);
		print_msg(tmpstr,&g_tRsComm[pt->chnl].sendbuf[1],g_tRsComm[pt->chnl].sendbuf[0]);
	}
}

static  void lnk_101_call_fixed(IECLINK_DEF *pt,unsigned char zone,bool bFCV)
{
	u8 *pd=pt->sendbuf;
	LNK_STATUS *ptlnk=&pt->tlnk;
	if(bFCV)
	{
		IEC101_SETFCV(zone);
		if(ptlnk->bMFCB)
		{
			IEC101_SETFCB(zone);  
		}
		else
		{
			IEC101_CLRFCB(zone);  
		}
	}

	if(!pt->b101Addr2Byte)
	{
		pd[0]=5;
		pd[1]=0x10;
		pd[2]=zone;
		pd[3]=(u8)pt->slave_addr;
		pd[4]=pd[2]+pd[3];
		pd[5]=0x16;
	}
	else
	{
		pd[0]=6;
		pd[1]=0x10;
		pd[2]=zone;
		pd[3]=(u8)pt->slave_addr;
		pd[4]=(u8)(pt->slave_addr>>8);
		pd[5]=pd[2]+pd[3]+pd[4];
		pd[6]=0x16;
	}
}


static void lnk_101_call(IECLINK_DEF *pt, u8 type,u8 ngd,u8 cot,u8 *pdat,u8 len)
{
	u8 *pd;
	u8 cnt,checksum;
	u8 zone=0x53;
	u8 tmplen;
	LNK_STATUS *ptlnk=&pt->tlnk;	
	tmplen=len+6;	
	// 报文长度调整变量赋值
	if(pt->b101Addr2Byte) tmplen++;		
	if(pt->b101Cot2Byte)  tmplen++;		
	if(pt->b101App2Byte)  tmplen++;
	
	if(ptlnk->bMFCB)
	{
		IEC101_SETFCB(zone);  
	}
	else
	{
		IEC101_CLRFCB(zone);  
	}
	pd=pt->sendbuf;		
	*pd++=tmplen+6;
	*pd++=0x68;
	*pd++=tmplen;
	*pd++=tmplen;
	*pd++=0x68;
	*pd++=zone;
	*pd++=(u8)pt->slave_addr;			//链路地址1
	if(pt->b101Addr2Byte)
	{
		*pd++=(u8)(pt->slave_addr>>8);	//链路地址2
	}
	*pd++=type;		//帧类型
	*pd++=ngd;  	//VSQ
	*pd++=cot;  	//传送原因
	if(pt->b101Cot2Byte)
	{
		*pd++=0;						//传送原因2	
	}
	*pd++=(u8)pt->slave_addr;		//应用服务单元地址1	
	if(pt->b101App2Byte)
	{
		*pd++=(u8)(pt->slave_addr>>8);	//应用服务单元地址2	
	}
	for(cnt=0;cnt<len;cnt++)  //标示拷贝
	{			
		*pd++=*pdat++;
	}
	checksum=0;
	pd=&pt->sendbuf[5];
	for(cnt=0;cnt<tmplen;cnt++)  //标示拷贝
	{			
		checksum+=*pd++;
	}
	*pd++=checksum;
	*pd++=0x16;	
}

#ifdef FUN_YPARA_CFG_NOTY
void lnk_para_chg(IECLINK_DEF *pt,u8 chnl,u8 vsq,u8 cot,u8 *ps,bool b104)
{
	int i =0,j=0;		
	u8 num=0;
	u8 off=0;
	u16 link_cp=0;
	int index=0;	
	para_chg_single	single;	
	struct rtc_time_t  ct;
	union{

		float ff;
		BYTE tt[4];
	}ff;

	num=(vsq&0x7f);
	memset(&single,0,sizeof(para_chg_single));		
	
	for(i=0;i<num;i++)
	{
/*点号*/
		link_cp=(ps[off]+(ps[off+1]<<8));		
		off += 2;				
		if(b104) off +=1;

/*值*/
		ff.tt[3] = ps[off++];
		ff.tt[2] = ps[off++];
		ff.tt[1] = ps[off++];
		ff.tt[0] = ps[off++];

/*时标*/		
		ct.ms=ps[off]+(ps[off+1]<<8);
		ct.min=ps[off+2];
		ct.hour=ps[off+3];
		ct.day=ps[off+4];
		ct.month=ps[off+5];
		ct.year=ps[off+6];	
		off += 7;	
		
		index = get_index_link(chnl,link_cp);
		if(index < 0)
		{			
			rt_printf("lnk_para_chg fail:chnl=0x%x,di=0x%x\r\n",chnl,link_cp);
			continue;
		}
		single.ct = ct;
		single.parId = tParaID[index].parId;
		single.val = ff.ff;	

		for(j=0;j<COMM_CHANNEL_NUM;j++)
		{
			add_data_queque(&g_para_chg_queque[j].queue,(u8 *)&single,OVER_QUEUE);	
		}
	}		
}
#endif

#ifdef	RCD_STRAN_M

bool lnk_qaddr_check(IECLINK_DEF *pt)
{
	u32 pos=0;
	QTYPE *queue;
	newrcd_m_struct data;

	queue = &pt->rcd_m.queue;
	if(queue->count == 0) return 0;	/*无数据*/

	pos = queue->front * queue->s_size;
	memcpy(&data, &queue->data[pos], queue->s_size);
	
	if(data.addr != pt->slave_addr) 
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

void lnk_rcdfile_check_104(IECLINK_DEF *pt)
{
	char tmp[100];
	newrcd_m_struct data;
	
	if(pt->tft.bTransing == false)	/*为该地址并且,没有文件在传输*/
	{
		if(get_queue_count(&pt->rcd_m.queue) > 0)
		{
			get_data_queque(&pt->rcd_m.queue,(u8 *)&data);
			
			strncpy(pt->tft.filename,data.filename,sizeof(pt->tft.filename));			
			pt->tft.fnamelen=strlen(pt->tft.filename);		
			pt->tft.bFile=true;		
			
			pt->tft.bTransing = true;		/*启动传输*/			
			pt->tft.addr = pt->slave_addr;		/*启动传输*/
			pt->tft.us0_file_trans = ustimer_get_origin();

			sprintf(tmp, "BAY%02d%s文件传输启动!!!!!!!", pt->chnl+1,pt->tft.filename+5);	/*104替换成级联通道号*/
			log_str_time(LOG_OPERATE,tmp,0,1); 
		}
	}
}

void lnk_rcdfile_check(IECLINK_DEF *pt)
{
	char tmp[100];
	newrcd_m_struct data;
	
	if(lnk_qaddr_check(pt) && (pt->tft.bTransing == false))	/*为该地址并且,没有文件在传输*/
	{
		if(get_queue_count(&pt->rcd_m.queue) > 0)
		{
			get_data_queque(&pt->rcd_m.queue,(u8 *)&data);
			
			strncpy(pt->tft.filename,data.filename,sizeof(pt->tft.filename));			
			pt->tft.fnamelen=strlen(pt->tft.filename);		
			pt->tft.bFile=true;		
			
			pt->tft.bTransing = true;		/*启动传输*/			
			pt->tft.addr = pt->slave_addr;		/*启动传输*/

			sprintf(tmp, "%s传输启动!!!",pt->tft.filename); 
			log_str_time(LOG_OPERATE,tmp,0,1); 
		}
	}
}


void lnk_rcdfile(IECLINK_DEF *pt,u8 *buf,u16 addr)
{
	char namestr[64]={0};
	u8 namelen=0,num=0;
	s32 i=0,off=0;
	newrcd_m_struct data;

	//strncpy(pt->tfile_m.dirpath,RCD_DIR,sizeof(pt->tfile_m.dirpath));	/*默认目录名*/
	num =buf[off++];

	for(i=0;i<num;i++)
	{
		namelen = buf[off++];		/*目录长*/	
		for(i=0;i<namelen;i++)		/*文件名*/
		{
			namestr[i]=buf[off++];		
		}			
		namestr[namelen]='\0';	
		
		strncpy(data.filename,namestr,sizeof(data));
		data.addr = addr;
		add_data_queque(&pt->rcd_m.queue,(u8 *)&data,OVER_QUEUE); 	
		
		//print_queque(&pt->rcd_m.queue,0);
	}
}
#endif

void lnk_101_app_recv(IECLINK_DEF *pt)
{
	u8 *pd;
	u8 AddByte=0;
	u8 CotByte=0;	//传送原因双字节
	u8 AppByte=0;	//应用单元地址双字节
	BYTE addr;
	LNK_STATUS *ptlnk=&pt->tlnk;	
	if(pt->bData)				//有接收到的数据
	{
		if(pt->b101Addr2Byte) AddByte=1;		
		if(pt->b101Cot2Byte)  CotByte=1;		
		if(pt->b101App2Byte)  AppByte=1;
	
		if(g_print_lnk && (g_print_port & (1<<pt->chnl)))
		{
			char tmpstr[24];
			sprintf(tmpstr,"RL_101(%d):",pt->chnl);
		
			if(pt->recvbuf[0]==0x10)  
			{
				print_msg(tmpstr,pt->recvbuf,5+AddByte);
			}
			else if(pt->recvbuf[0]==0xe5)  
			{
				print_msg(tmpstr,pt->recvbuf,1);
			}
			else
			{
				print_msg(tmpstr,pt->recvbuf,pt->recvbuf[1]+6);
			}	
		}
		
		pt->bData=false;

		// 检查帧类型
		if(pt->recvbuf[0]==0x10)  pd=&pt->recvbuf[1];//短帧
		else if(pt->recvbuf[0]==0x68)  pd=&pt->recvbuf[4];//长帧
		else if(pt->recvbuf[0]==0xe5)  pd=&pt->recvbuf[0];//长帧
		else 	return;

		// 根据类型标识处理长帧
		if(pt->recvbuf[0]==0x68)		
		{
			u8 chnl,asdu_addr=0;
			addr=pd[1];  //装置地址
			chnl=((pt->chnl+2)<<5)+addr;
			asdu_addr=pd[5+AddByte+CotByte];

			if(asdu_addr == addr)
			{
				switch(pd[2+AddByte]) //帧类型  pd[7]=ngd
				{ 
					case 1:			// 遥信帧:单点值
					case 3:			// 遥信帧:双点值
						lnk_slave_yx(chnl,pd[2+AddByte],pd[3+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte);
						break;
						
					case 9:			// 遥测帧:归一化值
					case 11:		// 遥测帧:标度化值
					case 13:		// 遥测帧:浮点值
					case 21:		// 遥测帧:不带品质描述字的归一化值
						lnk_slave_yc(chnl,pd[2+AddByte],pd[3+AddByte],2,pd+6+AddByte+CotByte+AppByte);
						break;
					case 206:			// 不带时标电度
					case 207:			//带时标 电度
						lnk_slave_dd(chnl,pd[2+AddByte],pd[3+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte);
						break;
					case 30:		// 事件记录:单点
					case 31:		// 事件记录:双点
					 	lnk_slave_soe(pt,chnl,pd[2+AddByte],pd[3+AddByte],2,pd+6+AddByte+CotByte+AppByte);
						break;	
						
					case 45:		// 遥控确认帧				
					case 46:		// 遥控确认帧
						lnk_slave_yk(chnl,pd[2+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte);
						break;
					
					case FOS_PAR_READ_ONE:
					case FOS_PAR_SET_ONE:
					case FOS_PAR_SET_MUL:
					case FOS_PAR_READ_MUL:
						lnk_slave_par(chnl,pd[2+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte,pd[3+AddByte]);
						break;
					
					case 42:		// 故障参数上送		
						lnk_slave_fault(chnl,pt->recvbuf[1]-6-AddByte-CotByte-AppByte,pd+6+AddByte+CotByte+AppByte,false);
						break;			
#ifdef YPARA_LINK
					case 202:
						lnk_slave_ypara_read(pt,chnl,pd[3+AddByte],pd[4+AddByte],pd+6+AddByte+CotByte+AppByte,false);
						break;
					case 203:
						//rt_printf("104级联读参数解包-------\r\n");
						lnk_slave_ypara_write(pt,chnl,pd[3+AddByte],pd[4+AddByte],pd+6+AddByte+CotByte+AppByte,false);
						break;				
#endif				

					case 210:		// 文件传输		
						lnk_test_file_frame(pt,&pt->recvbuf[12+AddByte+CotByte+AppByte],pt->recvbuf[1]-(AddByte+CotByte+AppByte)-9);
						break;						
					case 211:		// 文件下载
						lnk_update_file_frame(pt,pt->recvbuf[12+AddByte+CotByte+AppByte]);
						break;	
					case 70:		// 初始化结束帧
						ptlnk->bCallAll=true;
						break;	
				
			#ifdef	RCD_STRAN_M
					case IECLINK_RCD:	// 新录波帧
						lnk_rcdfile(pt,&pt->recvbuf[12+AddByte+CotByte+AppByte],addr);
					break;
			#endif

						
					
				}	
			}
			ptlnk->bEchoApp=(true&&pt->bPH101);
		}
		else if(pt->recvbuf[0]==0xe5)		
		{
			pt->recvbuf[0]=0;  // 防止影响: 设置1级数据标志
		}
		else
		{
			// 连接建立
			if((pd[0]&0x0f) == IEC101_ECHO_LINK_OK)
			{
				ptlnk->bLinkOK = true;
				pt->LinkCount++;
				rt_printf_time("101级联成功(通道=%d,连接计数=%d)!\r\n",pt->chnl,pt->LinkCount);
				ptlnk->dTCallAllTime=dTCounter;
			}
			else if(pt->bPH101)  // 平衡101
			{
				if((pd[0]&0xCf) == (IEC101_ECHO_NO_DATA|0xC0)) //召链路
				{
					ptlnk->bEchoLnk=true;
				}
				else if((pd[0]&0xCf) == (IEC101_REMOTE_RESET|0xC0)) //召链路
				{
					ptlnk->bEchoApp=true;
				}
				
			}			
		}
		// 请求链路状态必须得到正确的报文才允许继续往下走
		if(ptlnk->bLinkOK)
		{
			ptlnk->bMRecvOK=true;
		}
		ptlnk->dTInteral=dTCounter;

		// 设置1级数据标志
		if(pd[0]&0x20)  
		{
			ptlnk->bCallOne=(true&&!pt->bPH101);
		}
		ptlnk->dTSendTime=dTCounter;		
	}		
}

void lnk_101_salve_restore(IECLINK_DEF *pt,int pre,int m_current) //切换子站地址，并保存及恢复数据
{
	pt->tsla[pre].tlnksave=pt->tlnk;
	pt->tlnk=pt->tsla[m_current].tlnksave;
	pt->tlnk.bDdValid=pt->tsla[m_current].bDdValid;
	pt->slave_addr=pt->tsla[m_current].addr;
}

void lnk_101_change_slave(IECLINK_DEF *pt) //切换子站地址，并保存及恢复数据
{
	int m_current;
	LNK_STATUS *ptlnk=&pt->tlnk;	
	if(pt->slave_num<=1)
	{
		ptlnk->bDdValid=pt->tsla[0].bDdValid;
		return;	//只有一个子站地址，不切换
	}
	if(ptlnk->bCallOne)  return;		//有一级数据需继续召唤，不切换子站地址
	m_current=pt->slave_current;
	m_current++;
	if(m_current>=pt->slave_num)m_current=0;
	pt->slave_addr=pt->tsla[m_current].addr;
	lnk_101_salve_restore(pt,pt->slave_current,m_current);
	pt->slave_current=m_current;
}
void lnk_101_app_send(IECLINK_DEF *pt)
{

	LNK_STATUS *ptlnk=&pt->tlnk;
	bool bWantEcho=true;
	
	if(pt->slave_num==0)return;		

#ifdef	RCD_STRAN_M
	if((pt->tft.bTransing == false)					/*有文件正在传输,加速召唤*/
		&&(dTCounter-ptlnk->dTSendTime<pt->sendinteraltime))
	{
		return;
	}						
#else
	if((dTCounter-ptlnk->dTSendTime) <pt->sendinteraltime)    // 接收到报文后，发送间隔
	{
		return;
	}
#endif
	
	// 检查从机应答
	if(ptlnk->bMSend)  
	{
		if(!ptlnk->bMRecvOK) 
		{
			// 如果超时未收到应答，重发
			if(dTCounter-ptlnk->dTMWait>pt->retrytime)  
			{
				ptlnk->dTMWait=dTCounter;	
				
				//重发三次后,重新初始化
				if(++ptlnk->byRetryTimes>2||ptlnk->bRetryErr)  
				{
					ptlnk->bMSend=false;
					ptlnk->bCallLnk=true;	
					ptlnk->bRetryErr=true;					
					if(ptlnk->bLinkOK)
					{					
					#ifdef	RCD_STRAN_M
						if((pt->tft.bTransing) && (pt->tft.addr == pt->slave_addr))	/*通道中断,重新召唤*/
						{
							log_str_time(LOG_OPERATE,"通讯断开,中断传输",0,1); 
							pt->tft.bTransing = false;	
						}																							
					#endif
						ptlnk->bLinkOK = false;
						rt_printf_time("重发失败，复位链路(通道=%d,连接计数=%d)!\r\n",pt->chnl,pt->LinkCount);
					}
				}
				else
				{
					//需重新组织发送
					lnk_101_send(pt);			
				}
			}
			// 发送，未收到数据，返回
			return;	
		}
		else
		{
			ptlnk->bRetryErr=false;
		}
	}

	lnk_101_change_slave(pt);
	
#ifdef	RCD_STRAN_M
	if(ptlnk->bLinkOK)
	{		
		lnk_rcdfile_check(pt);
	}
#endif

	// 上一帧从机应答OK，开始下一帧发送
	ptlnk->bMSend=false;

	if(ptlnk->bEchoApp)
	{
		 lnk_101_call_fixed(pt,IECLINK_ECHOAPP,false);
		 ptlnk->bEchoApp=false;
		 bWantEcho=false;
	}
	else if(ptlnk->bEchoLnk)
	{
 		lnk_101_call_fixed(pt,IECLINK_ECHOLNK,false);
		 ptlnk->bEchoLnk=false;
		  bWantEcho=false;
	}	
	else if(ptlnk->bCallLnk)
	{
		lnk_101_call_fixed(pt,IECLINK_CALLLNK,false);
		ptlnk->bMFCB=false;
		ptlnk->bCallLnk=false;
		ptlnk->bCallRst=true;		
	}
	else if(ptlnk->bCallRst)
	{
		lnk_101_call_fixed(pt,IECLINK_CALLRST,false);
		ptlnk->bMFCB=false;
		ptlnk->bCallRst=false;
		if(!pt->bPH101)
		{
			ptlnk->bCallAll=true;		
			ptlnk->bSetTime=true;
#ifdef YPARA_LINK
			set_read_all(pt);
#endif
		}
	}
	else if(ptlnk->bCallOne)
	{
		lnk_101_call_fixed(pt,IECLINK_CALLONE,true);
		ptlnk->bCallOne=false;
	}
	else if(ptlnk->bCallAll)
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0x14;
		lnk_101_call(pt,100,1,6,dat,num);
		ptlnk->bCallAll=false;
		ptlnk->bCallDD=true;	
		ptlnk->dTCallAllTime=dTCounter;
	}
	else if(ptlnk->brst)
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0x14;
		lnk_101_call(pt,176,1,6,dat,num);
		ptlnk->brst=false;
	}	
	else if(ptlnk->bCallDD&&ptlnk->bDdValid)
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0x05;
		lnk_101_call(pt,101,1,6,dat,num);
		ptlnk->bCallDD=false;
	}	
	else if(ptlnk->bSetTime)
	{
		u8 dat[12];
		int num=0;
		struct timespec ts;
		struct rtc_time_t rtc;
		clk_time_get(&ts);
		timespec_to_rtc(ts,&rtc,1);
		dat[num++]=0;				//信息序号=0时钟同步		
		dat[num++]=0;				//信息序号=0时钟同步
		dat[num++]=(u8)rtc.ms;		//MsL
		dat[num++]=(u8)(rtc.ms>>8);	//MsH
		dat[num++]=rtc.min;			//Min
		dat[num++]=rtc.hour;			//hour
		dat[num++]=rtc.day;			//Day
		dat[num++]=rtc.month;		//month
		dat[num++]=rtc.year;			//year				
		lnk_101_call(pt,103,1,6,dat,num);
		ptlnk->bSetTime=false;
		ptlnk->us0_set_time = ustimer_get_origin();
	}		
	// 遥控
	else if(pt->yk_send_flag)
	{
		u8 dat[12];
		int i,num=0;

		for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
		{
			if(pt->yk_send_flag & (1<<i))
			{
				u8 addr;
				num=0;
				addr=g_lnk_yk[i].chnl&0x1f;

				if(addr!=pt->slave_addr)continue;				
			
				dat[num++]=(u8)g_lnk_yk[i].cp_s;			
				dat[num++]=(u8)(g_lnk_yk[i].cp_s>>8); 		

				// 远动选择
				if(g_lnk_yk[i].data[IECLINK_YK_SND].ti == 0xff)
				{
					dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v|0x80;	
					lnk_101_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1);
					g_lnk_yk[i].data[IECLINK_YK_SND].ti = 0xfe;
					
				}
				// 远动遥控
				else if(g_lnk_yk[i].data[IECLINK_YK_SND].ti == 0xfe)
				{
					dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v;	
					lnk_101_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1);
					
					// 清除标志 
					g_lnk_yk[i].flag[IECLINK_YK_SND]=false;				
					pt->yk_send_flag &= ~(1<<i);
				}	
				//主站遥控
				else
				{
					dat[num++]=g_lnk_yk[i].data[IECLINK_YK_SND].v;	
					lnk_101_call(pt,g_lnk_yk[i].data[IECLINK_YK_SND].ti,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num);
					
					// 清除标志 
					g_lnk_yk[i].flag[IECLINK_YK_SND]=false;				
					pt->yk_send_flag &= ~(1<<i);
				}

				ptlnk->bMSend=true;
				break;
			}
		}
	}
	// 遥参
	else if(pt->par_send_flag)
	{
		u8 dat[256];
		int i,num=0;

		for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
		{
			if(pt->par_send_flag & (1<<i))
			{
				u8 addr;
				num=0;
				addr=g_link_par[i].chnl&0x1f;

				if(addr!=pt->slave_addr)continue;				
			
				//dat[num++]=(u8)g_link_par[i].cp_s;			
				//dat[num++]=(u8)(g_link_par[i].cp_s>>8); 		

				// 远动选择
				if(g_link_par[i].data[IECLINK_YK_SND].ti == 0xff)
				{
					int count;
					//dat[num]=g_link_par[i].data[IECLINK_YK_SND].v|0x80;	
					memcpy(&dat[num],&g_link_par[i].data[IECLINK_YK_SND].buf,g_link_par[i].data[IECLINK_YK_SND].len);

					rt_printf("参数选择      \r\n");
					for (count=0;count<g_link_par[i].data[IECLINK_YK_SND].len;count++)
						rt_printf("%02X ",dat[num+count]);
					
					num += g_link_par[i].data[IECLINK_YK_SND].len;
					
					//vsq=1;//ngd
					lnk_101_call(pt,g_link_par[i].data[IECLINK_YK_SND].ti_m,g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].cot,dat,num);

					//g_link_par[i].data[IECLINK_YK_SND].ti = 0xfe;

					// 清除标志 
					#ifdef FUNC_MORE_PREREAD	
						pt->dtpartime[i]=ustimer_get_origin();
					#endif
					pt->par_send_flag &= ~(1<<i);
				}
				// 远动
				else if(g_link_par[i].data[IECLINK_YK_SND].ti == 0xfe)
				{
					//dat[num]=g_link_par[i].data[IECLINK_YK_SND].v;
					memcpy(&dat[num],g_link_par[i].data[IECLINK_YK_SND].buf,g_link_par[i].data[IECLINK_YK_SND].len);
					num += g_link_par[i].data[IECLINK_YK_SND].len;
					lnk_101_call(pt,g_link_par[i].data[IECLINK_YK_SND].ti_m,g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].cot,dat,num);
					rt_printf("参数激活\r\n");
					g_link_par[i].data[IECLINK_YK_SND].ti = 0;
					// 清除标志 
					// 清除标志 
					#ifdef FUNC_MORE_PREREAD	
						pt->dtpartime[i]=ustimer_get_origin();
					#else				
						g_link_par[i].flag[IECLINK_YK_SND]=false;	
					#endif			
					pt->par_send_flag &= ~(1<<i);
				}	
				//主站遥控
				else
				{
					//dat[num++]=g_link_par[i].data[IECLINK_YK_SND].v;	
					memcpy(&dat[num],g_link_par[i].data[IECLINK_YK_SND].buf,g_link_par[i].data[IECLINK_YK_SND].len);
					num += g_link_par[i].data[IECLINK_YK_SND].len;
					rt_printf("主站下发遥参定值\r\n");
					lnk_101_call(pt,g_link_par[i].data[IECLINK_YK_SND].ti_m,g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].cot,dat,num);
					
					// 清除标志 
					#ifdef FUNC_MORE_PREREAD	
						pt->dtpartime[i]=ustimer_get_origin();
					#else				
						g_link_par[i].flag[IECLINK_YK_SND]=false;	
					#endif
					pt->par_send_flag &= ~(1<<i);
				}

				ptlnk->bMSend=true;
				break;
			}
		}
	}
#ifdef YPARA_LINK
	//遥参
	else if(get_queue_count(&pt->par_queue.queue) > 0)
	{	
		u8 dat[256];
		int i=0,num=0;
		msg_data_struct	*msg =&pt->temp_par;			
		msg_ypara_data_struct 	*ypara_msg = &msg->ypara_msg;

		//rt_printf("[%d]:::101遥参下发-----par_queue  num=%d,[%x,%x]\r\n",pt->chnl,get_queue_count(&pt->par_queue.queue),msg->dport &0x1f,pt->slave_addr);
		check_data_queque(&pt->par_queue.queue,(u8 *)msg);
		if((msg->dport &0x1f) != pt->slave_addr)		/*非当前地址*/
		{			
			return;
		}
		del_data_queue(&pt->par_queue.queue);
		
		
		if(ypara_msg->type == modify_set)
		{	
			/*定值区*/
			dat[num++] = (u8)ypara_msg->section_p;
			dat[num++] = (u8)(ypara_msg->section_p>>8);
		
			if(ypara_msg->cmd == YP_SEL)
			{				
				dat[num++] = 0x80; /*特征码*/
				for(i=0;i<ypara_msg->num;i++)
				{
					dat[num++]=(u8)ypara_msg->base_data[i].cp_s;
					dat[num++]=(u8)(ypara_msg->base_data[i].cp_s>>8);
					dat[num++] = ypara_msg->base_data[i].val_iec.tag;
					dat[num++] = ypara_msg->base_data[i].val_iec.size;					
					if(ypara_msg->base_data[i].val_iec.size >0)
					{						
						memcpy(&dat[num],ypara_msg->base_data[i].val_iec.value,ypara_msg->base_data[i].val_iec.size); 				
						num += ypara_msg->base_data[i].val_iec.size; 						
					}																		
				}	
			}
			else if(ypara_msg->cmd == YP_EXE)
			{	
			
				dat[num++] = 0; /*特征码*/			
				set_read_all(pt);
			
			}	
			else
			{			
				dat[num++] = 0x40; /*特征码*/
			}


			if((ypara_msg->cmd == 2) || (ypara_msg->cmd == 1))
			{				
				lnk_101_call(pt,203,ypara_msg->num,6,dat,num);
			}
			else
			{		
				lnk_101_call(pt,203,ypara_msg->num,8,dat,num);
			}

			
 			pt->sport	= msg->sport;
			ptlnk->bMSend=true; 
			
		}
		else if(ypara_msg->type == settion_swht)	//切换定值区
		{




		}		 		
		 
					
	}
	else if(ptlnk->bSet_all)
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;	//当前定值区
		dat[num++]=0;	//当前定值区		
		lnk_101_call(pt,202,0,6,dat,num);			
		clear_read_all(pt);
		ptlnk->bMSend=true; 
	}
#endif
#ifdef	RCD_STRAN_M
	else if((ptlnk->bRcd)
		&& (get_queue_count(&pt->rcd_m.queue) <= 0) && (pt->tft.bTransing == false)
		&& (tRunPara.b_lb_master || (pt->b_lb_master)))		/*没有文件传输*/
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;
		dat[num++]=0;
		lnk_101_call(pt,IECLINK_RCD,1,6,dat,num);
		ptlnk->bRcd=false;
	}
	// 空闲时，以500ms间隔召二级数据
	else if((lnk_file_check_trans(pt)) && (pt->tft.addr == pt->slave_addr))
	{
		rt_printf("---------文件传输%d\r\n",pt->slave_addr);
		lnk_test_file_trans(pt);
	}
	else if((pt->tft.bTransing == true)&&(pt->tft.addr == pt->slave_addr))					/*有文件正在传输,加速召唤*/		
	{
		if(!pt->bPH101)  
		{
			lnk_101_call_fixed(pt,IECLINK_CALLTWO,true);
		}
		else
		{
			return;
		}
	}
#else
	// 空闲时，以500ms间隔召二级数据
	else if(lnk_file_check_trans(pt))
	{
		lnk_test_file_trans(pt);
	}
#endif	
	else if(dTCounter-ptlnk->dTInteral>pt->sendinteraltime)
	{
	
		if(!pt->bPH101)  
		{
			lnk_101_call_fixed(pt,IECLINK_CALLTWO,true);
		}
		else
		{
			return;
		}
	}	
	else
	{
		return;
	}

	// 开始发送，清重发标志，翻转FCB位
	ptlnk->bMSend=true&& bWantEcho;
	ptlnk->bMRecvOK=false;
	ptlnk->dTMWait=dTCounter;	
	ptlnk->byRetryTimes=0;	
	if(bWantEcho)	ptlnk->bMFCB=!ptlnk->bMFCB;
	lnk_101_send(pt);			
}

void lnk_101_par_timer(IECLINK_DEF *pt)
{
	int i=0;
	int flag=0;
	
	for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
	{
		flag = pt->par_send_flag & (1<<i);
		if(g_link_par[i].flag[IECLINK_YK_SND] && !flag) 	
		{		
			if(ustimer_get_duration(pt->dtpartime[i]) > 10*USTIMER_SEC)	/*10秒遥参*/
			{
				rt_printf("--------遥参超时!!!\r\n");
				g_link_par[i].flag[IECLINK_YK_SND] = false;			
			}			
		}
	}
}
 
void lnk_101_app_timer(IECLINK_DEF *pt)
{
	LNK_STATUS *ptlnk=&pt->tlnk;

	// 定时总召	
	if(!ptlnk->bCallAll)
	{
		if(dTCounter-ptlnk->dTCallAllTime>pt->callalltime)  //  10分钟总召一次
		{
			ptlnk->bCallAll=true;		
			ptlnk->dTCallAllTime=dTCounter;
		}
	}
	
#ifdef	RCD_STRAN_M
	if(ustimer_get_duration(ptlnk->dTRcdTime) > 3*USTIMER_SEC)	/*3秒间隔*/
	{
		ptlnk->bRcd = true;		
		ptlnk->dTRcdTime=ustimer_get_origin();		
	}
#endif

#ifdef FUNC_MORE_PREREAD
	//lnk_101_par_timer(pt);	
#endif
	
	// 检查对时间隔
	if(ustimer_get_duration(ptlnk->us0_set_time) > 5*60*USTIMER_SEC)
	{
		ptlnk->bSetTime = true;
	}

}

void lnk_101_app(IECLINK_DEF *pt)
{
	LNK_STATUS *ptlnk=&pt->tlnk;

	lnk_101_app_recv(pt);
	lnk_101_app_send(pt);

	if(ptlnk->bLinkOK)
	{
		lnk_101_app_timer(pt);	
	}
}

static void lnk_101_recv_rst(IECLINK_DEF *pt)
{
	pt->nTypeCounter=0;
	pt->nRecvLenth=0;
	pt->nRecvCounter=0;
}


void lnk_101_recv(IECLINK_DEF *pt,u8 byRevData) 
{
	pt->recvbuf[pt->nRecvCounter++]=byRevData;
	switch(pt->nTypeCounter)
	{
		case 0:
		if(byRevData==0x68)
		{
			pt->nTypeCounter=1;
			pt->sum=0;		
		}
		else if(byRevData==0x10)
		{
			if(!pt->b101Addr2Byte)
			{
				pt->nRecvLenth=2;
			}
			else
			{
				pt->nRecvLenth=3;
			}				
			pt->nTypeCounter=6;
			pt->nRecvCnt=0;	
			pt->sum=0;		
		}
		else if(byRevData==0xe5)  //  e5处理
		{
			lnk_101_recv_rst(pt);
			pt->bData=true;
			// 唤醒主循环
			mainloop_wakeup();
		}
		else
		{
			lnk_101_recv_rst(pt);
		}
		break;
		case 1:
			pt->nTypeCounter=2;
			pt->nRecvLenth=byRevData;			//长帧长度
			if(pt->nRecvLenth>IECLINK_RECVBUF_MAX)
			{
				lnk_101_recv_rst(pt);
			}
			break;
		case 2:
			if(pt->nRecvLenth==byRevData)
			{
				pt->nTypeCounter=3;
			}
			else
			{
				lnk_101_recv_rst(pt);
			}
			break;
		case 3:
			if(byRevData==0x68)
			{
				pt->nTypeCounter=6;
				pt->nRecvCnt=0;	
			}
			else
			{
				lnk_101_recv_rst(pt);
			}
			break;
		//case 4:  //控制域
		//	pt->sum=byRevData;
		//	pt->nTypeCounter=5;
		//	break;
		//case 5: //目标地址
		//		pt->sum+=byRevData;
		//		pt->nRecvCnt=0;
		//		pt->nTypeCounter=6;
		//		if(pt->nRecvLenth==2)//短帧 
		//			pt->nTypeCounter=7;
		//	break;
		case 6:	 //有效数据			//有效数据
			if(++pt->nRecvCnt>=pt->nRecvLenth)
			{
				pt->nTypeCounter=7;
			}
			pt->sum+=byRevData;
			break;
		case 7:		 //校验和	
			if(pt->sum==byRevData)
			{
				pt->nTypeCounter=8;
			}
			else
			{
				lnk_101_recv_rst(pt);
			}
			break;
		case 8:  //结束符
			lnk_101_recv_rst(pt);
			if(byRevData==0x16)	//校验结束字符,报文接收完毕，
			{
				pt->bData=true;
				// 唤醒主循环
				mainloop_wakeup();
				return ;
			}
			break;
		}
}	


//  下面是以太网级联代码
void lnk_104_init(int net)
{
	IECLINK_DEF *pt = &g_link_104[net];	
	LNK_STATUS *ptlnk=&pt->tlnk;	
	memset(pt,0,sizeof(IECLINK_DEF));
	pt->type=IEC104_CHN;
	pt->chnl = net;
	pt->sendbuf=g_link104_buf[net];
	ptlnk->bCallRst=true;
	ptlnk->dTMWait=dTCounter;
	ptlnk->dTInteral=dTCounter;
	ptlnk->dTCallAllTime=dTCounter;

	ptlnk->us0_set_time=ustimer_get_origin();	
	
	// 测试状态复位
	pt->bStartTest=false;
	pt->us0_test=ustimer_get_origin();	
	lnk_init_cfg(pt,"IEC104_LNK");
	pt->AckRecvNum=0;
#ifdef RCD_STRAN_M
	queue_init(&pt->rcd_m.queue,NEWRCD_COUNT_M,&pt->rcd_m.data,NEWRCD_SIZE_M);
#endif
#ifdef YPARA_LINK
	queue_init(&pt->par_queue.queue,PAR_COUNT_M,&pt->par_queue.data,PAR_SIZE_M);
#endif

}


void lnk_104_send(IECLINK_DEF *pt,u8 num)
{
	char tmpstr[16];
	sprintf(tmpstr,"TL_104(%d):",pt->chnl+1);
	if(g_print_lnk && (g_print_port & (1<<pt->chnl)))
	{
		print_msg(tmpstr,pt->sendbuf,num);
	}
	net_104link_send(pt->chnl,pt->sendbuf,num);

	// 发送了任意帧，复位T3定时器(测试帧超时)
	pt->us0_test=ustimer_get_origin();
}


static void lnk_104_ack(IECLINK_DEF *pt,u8 zone)
{
	u8 *pd=pt->sendbuf;
	int sum=0;
	pd[sum++]=0x68;
	pd[sum++]=0x04;
	pd[sum++]=zone;
	pd[sum++]=0x00;
	pd[sum++]=0x00;
	pd[sum++]=0x00;
	lnk_104_send(pt,sum);
}

static void lnk_104_sAck(IECLINK_DEF *pt)
{
	u8 *pd=pt->sendbuf;
	int sum=0;
	pd[sum++]=0x68;
	pd[sum++]=0x04;
	pd[sum++]=0x01;
	pd[sum++]=0x00;
	sum += CopySwap(&pd[sum],pt->RecvNum.tt,2,true);
	pt->AckRecvNum=pt->RecvNum.ss;
	lnk_104_send(pt,sum);
}

static void lnk_104_call(IECLINK_DEF *pt, u8 type,u8 ngd,u8 cot,u8 *pdat,u8 len)
{
	u8 *pd;
	int sum=0;
	int i;
	pd=pt->sendbuf; 

	//68 14 00 00 00 00 67 01 06 01 01 00 00 00 00 34 df 1d 0e 51 09 0d  //对时
	//68 0e 02 00 04 00 64 01 06 01 01 00 00 00 00 14 //总招
	//68 0e 04 00 4c 00 2e 01 06 01 01 00 01 60 00 82 //遥控

	pd[sum++]=0x68;
	pd[sum++]=len+10;
	sum += CopySwap(&pd[sum],pt->SendNum.tt,2,true);	
	sum += CopySwap(&pd[sum],pt->RecvNum.tt,2,true);
	
	pd[sum++]=type;//帧类型
	pd[sum++]=ngd;
	pd[sum++]=cot;	
	pd[sum++]=0;
	pd[sum++]=(u8)1; // 使用1作为级联从机的地址
	pd[sum++]=(u8)0;
	for(i=0;i<len;i++)  //标示拷贝
	{			
		pd[sum++]=*pdat++;
	}
	pt->AckRecvNum=pt->RecvNum.ss;
	lnk_104_send(pt,sum);
	pt->SendNum.ss+=2;
	pt->bSendS = 0;
}



void lnk_104_app_recv(int net)
{
	IECLINK_DEF *pt = &g_link_104[net];
	u8 *pd,addr;
	Byte2WORD Num;
	LNK_STATUS *ptlnk=&pt->tlnk;
	char tmpstr[16];
	if(pt->bData == 0)				//有接收到的数据
	{
		return;
	}
	
	sprintf(tmpstr,"RL_104(%d):",pt->chnl+1);
	if(g_print_lnk && (g_print_port & (1<<pt->chnl)))
	{
		print_msg(tmpstr,pt->recvbuf,pt->recvbuf[1]+2);
	}
	
	if(pt->recvbuf[0] != 0x68)
	{
		pt->bData=false;
		g_net_104link_data[net]=0;
		return;
	}

	switch(pt->recvbuf[2]&0x03)	//控制域判断
	{
		case 0x00:			//I格式
		case 0x02:
		// 确认发送帧的接收序号
		pt->recvbuf[2] &= 0xfe;
		CopySwap(Num.tt,&pt->recvbuf[2],2,false);
		Num.ss += 2;

		if(Num.ss != pt->RecvNum.ss)
		{
			if(pt->bSendS == 0)
			{
				ptlnk->dTInteral=dTCounter;
			}
			
			pt->bSendS = ((Num.ss - pt->RecvNum.ss) > 8*2)? 2 : 1;
			pt->RecvNum.ss = Num.ss;
		}

		//确认序号
		pt->recvbuf[4] &= 0xfe;
		CopySwap(pt->AckNum.tt,&pt->recvbuf[4],2,false);

		// 处理ASDU
		pd=&pt->recvbuf[6];
		addr=pt->chnl+1;			// 网络通道，统一使用网络1，级联地址代表参数表中子站地址，下发从1开始，pt->chnl从0开始
		switch(pd[0]) 
		{ 
			case 1: 		// 遥信帧:单点值
			case 3: 		// 遥信帧:双点值
				lnk_slave_yx(addr,pd[0],pd[1],pd[2],3,pd+6);
				break;
				
			case 9: 		// 遥测帧:归一化值
			case 11:		// 遥测帧:标度化值
			case 13:		// 遥测帧:浮点值
				lnk_slave_yc(addr,pd[0],pd[1],3,pd+6);
				break;
				
			case 30:		// 事件记录:单点
			case 31:		// 事件记录:双点
				lnk_slave_soe(pt,addr,pd[0],pd[1],3,pd+6);
				break;	
				
			case 45:		// 遥控确认帧				
			case 46:		// 遥控确认帧
				lnk_slave_yk(addr,pd[0],pd[2],3,pd+6);
				break;
			case FOS_PAR_READ_ONE:
			case FOS_PAR_SET_ONE:
			case FOS_PAR_SET_MUL:
			case FOS_PAR_READ_MUL:
				lnk_slave_par(addr,pd[0],pd[2],3,pd+6,pd[1]);
				break;
			case FOS_PAR_READ_ONE_EXT:
			case FOS_PAR_SET_ONE_EXT:
			case FOS_PAR_SET_MUL_EXT:
			case FOS_PAR_READ_MUL_EXT:
				lnk_slave_par(addr,pd[0],pd[2],2,pd+6,pd[1]);			
				break;
			
#ifdef FUN_YPARA_CFG_NOTY
			case 116:				
				lnk_para_chg(pt,addr,pd[1],pd[2],pd+6,true);
				break;
#endif
			
#ifdef YPARA_LINK
			case 202:
				lnk_slave_ypara_read(pt,addr,pd[1],pd[2],pd+6,true);
				break;
			case 203:
				//rt_printf("104级联读参数解包-------\r\n");
				lnk_slave_ypara_write(pt,addr,pd[1],pd[2],pd+6,true);
				break;
			case SET_UP_TYPE:
				if(pd[2] & IEC_COT_PN)		break;
				lnk_slave_ypara_updata(pt,pd+6);
				break;
#endif
		
#ifdef	RCD_STRAN_M
			case IECLINK_RCD:	// 新录波帧 			
				ptlnk->bRcding = false;
				if(pd[2] & IEC_COT_PN)		break;					
				lnk_rcdfile(pt,&pt->recvbuf[15],tRunPara.byAddr);																					
			break;				
#endif
		
			case 206:			// 不带时标电度
			case 207:			//带时标 电度
				lnk_slave_dd(addr,pd[0],pd[1],pd[2],3,pd+6);
			break;

			case 42:		// 故障参数上送		
				lnk_slave_fault(addr,pt->recvbuf[1]-10,pd+6,true);
				break;	
			case 210:		// 文件传输		
				lnk_test_file_frame(pt,&pt->recvbuf[15],pt->recvbuf[1]-14);
				break;
			case 211:		// 文件传输		
				lnk_update_file_frame(pt,pt->recvbuf[15]);
				break;

				
				
		}	
		break;	
		
		case 0x01:			//S格式		
			pt->recvbuf[4] &= 0xfe;
			CopySwap(pt->AckNum.tt,&pt->recvbuf[4],2,false);	
			break;
		case 0x03:			//U格式	
			// 如果是子站主动发送的测试帧，必须应答
			if(pt->recvbuf[2] == FRAME_U_TEST)
			{
				pt->bTestAck = true;
			}
			break;
			
	}
	
	ptlnk->bMRecvOK=true;
	ptlnk->byRetryTimes=0;

	// 清Test计数器	
	pt->us0_test=ustimer_get_origin();			 
	pt->bStartTest=false;		

	pt->bData=false;
	g_net_104link_data[net]=0;
}

void lnk_104_app_send(int net)
{
	IECLINK_DEF *pt = &g_link_104[net];
	LNK_STATUS *ptlnk=&pt->tlnk;
	
	// 以下开始处理发送
	// 检查从站应答
	if(ptlnk->bMSend && (!ptlnk->bMRecvOK))	
	{
		if(dTCounter-ptlnk->dTMWait>pt->retrytime)   // 2秒后，未收到应答报文
		{
			ptlnk->dTMWait=dTCounter;	
			ptlnk->bMSend=false;
			ptlnk->bCallRst=true;	
#ifdef	RCD_STRAN_M
			if(pt->tft.bTransing)	/*通道中断,重新召唤*/
			{
				log_str_time(LOG_OPERATE,"通讯断开,中断传输",0,1); 
				pt->tft.bTransing = false;	
			}																							
#endif
		}

		// 从站未应答，直接返回
		return; 
	}

	// 到这儿，以前的发送帧已应答完成，开始新的发送
	// 先初始化数据
	ptlnk->byRetryTimes=0;
	ptlnk->dTMWait=dTCounter;	
	ptlnk->bMRecvOK=false;
	ptlnk->bMSend=false;
#ifdef	RCD_STRAN_M
	lnk_rcdfile_check_104(pt);	/*扫描是否有录波文件召唤*/
#endif

	// 进入STARTDT状态
	if(ptlnk->bCallRst)
	{
		lnk_104_ack(pt,0x07);
		
		ptlnk->bCallRst=false;
		ptlnk->bMSend=true;
		
		ptlnk->bCallAll=true;
		ptlnk->bSetTime=true;
#ifdef YPARA_LINK
		set_read_all(pt);
#endif
		pt->SendNum.ss=0;
	}
	// 总召
	else if(ptlnk->bCallAll)
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0x14;
		lnk_104_call(pt,100,1,6,dat,4);
		ptlnk->bCallAll=false;
		ptlnk->bCallDD=true;	
		ptlnk->dTCallAllTime=dTCounter;
		ptlnk->bMSend=true;
	}
	else if(ptlnk->bCallDD)
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0x05;
		lnk_104_call(pt,101,1,6,dat,4); //电度召唤
		ptlnk->bCallDD=false;
		ptlnk->bMSend=true;
	}
	// 对时
	else if(ptlnk->bSetTime)
	{
		u8 dat[12];
		int num=0;
		struct timespec ts;
		struct rtc_time_t rtc;
		clk_time_get(&ts);
		timespec_to_rtc(ts,&rtc,1);		
		
		dat[num++]=0;				//信息序号=0时钟同步		
		dat[num++]=0;				//信息序号=0时钟同步
		dat[num++]=0;				//信息序号=0时钟同步				
		dat[num++]=(u8)rtc.ms;		//MsL
		dat[num++]=(u8)(rtc.ms>>8);	//MsH
		dat[num++]=rtc.min; 		//Min
		dat[num++]=rtc.hour;			//hour
		dat[num++]=rtc.day; 		//Day
		dat[num++]=rtc.month;		//month
		dat[num++]=rtc.year;			//year				
		lnk_104_call(pt,103,1,6,dat,num);
		ptlnk->bSetTime=false;
		ptlnk->bMSend=true;

		ptlnk->us0_set_time = ustimer_get_origin();
	}			
	// 遥控
	else if(pt->yk_send_flag)
	{
		u8 dat[12];
		int i,num=0;

		for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
		{
			if(pt->yk_send_flag & (1<<i))
			{
				dat[num++]=(u8)g_lnk_yk[i].cp_s;			
				dat[num++]=(u8)(g_lnk_yk[i].cp_s>>8); 		
				dat[num++]=0;

				if(g_lnk_yk[i].data[IECLINK_YK_SND].ti == 0xff)
				{
					dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v|0x80;	
					lnk_104_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1);
					dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v;	
					lnk_104_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1);
					
				}
				else
				{
					dat[num++]=g_lnk_yk[i].data[IECLINK_YK_SND].v;	
					lnk_104_call(pt,g_lnk_yk[i].data[IECLINK_YK_SND].ti,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num);
				}

				g_lnk_yk[i].flag[IECLINK_YK_SND]=false;				
				ptlnk->bMSend=true;

				// 清除标志 
				pt->yk_send_flag &= ~(1<<i);
				break;
			}
		}
	}
	else if(pt->par_send_flag)
	{
		u8 dat[256];
		int i,num=0;
		int len=0;

		for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
		{
			if(pt->par_send_flag & (1<<i))
			{
				u8 ti_m=0;
				num=0;
				
				// 远动选择
				if(g_link_par[i].data[IECLINK_YK_SND].ti == 0xff)
				{
					int count;

				#ifdef FOS_PAR_EXT
					memcpy(&dat[num],&g_link_par[i].data[IECLINK_YK_SND].buf,g_link_par[i].data[IECLINK_YK_SND].len);
					len = g_link_par[i].data[IECLINK_YK_SND].len;
					if(g_link_par[i].data[IECLINK_YK_SND].ti_m==FOS_PAR_SET_MUL)
					{
						ti_m = FOS_PAR_SET_MUL_EXT;
					}
					else if(g_link_par[i].data[IECLINK_YK_SND].ti_m==FOS_PAR_SET_ONE)
					{
						ti_m = FOS_PAR_SET_ONE_EXT;
					}
					else if(g_link_par[i].data[IECLINK_YK_SND].ti_m==FOS_PAR_READ_ONE)
					{
						ti_m = FOS_PAR_READ_ONE_EXT;
					}
					else if(g_link_par[i].data[IECLINK_YK_SND].ti_m==FOS_PAR_READ_MUL)
					{
						ti_m = FOS_PAR_READ_MUL_EXT;
					}	
				#else				
					len = get_par_link_101_to_104(&dat[num],&g_link_par[i].data[IECLINK_YK_SND].buf[0],g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].ti_m);	
					ti_m = g_link_par[i].data[IECLINK_YK_SND].ti_m;
				#endif	
				
					num += len;
					rt_printf("参数选择      \r\n");
					for (count=0;count<len;count++)
						rt_printf("%02X ",dat[num+count]);									
					
					lnk_104_call(pt,ti_m,g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].cot,dat,num);
					// 清除标志 
					#ifdef FUNC_MORE_PREREAD	
						pt->dtpartime[i]=ustimer_get_origin();
					#endif
					pt->par_send_flag &= ~(1<<i);
				}
				// 远动
				else if(g_link_par[i].data[IECLINK_YK_SND].ti == 0xfe)
				{
					//dat[num]=g_link_par[i].data[IECLINK_YK_SND].v;
					len = get_par_link_101_to_104(&dat[num],&g_link_par[i].data[IECLINK_YK_SND].buf[0],g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].ti_m);
					num += len;					
					lnk_104_call(pt,g_link_par[i].data[IECLINK_YK_SND].ti_m,g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].cot,dat,num);
					rt_printf("参数激活\r\n");
					g_link_par[i].data[IECLINK_YK_SND].ti = 0;
					// 清除标志 
					// 清除标志 
					#ifdef FUNC_MORE_PREREAD	
						pt->dtpartime[i]=ustimer_get_origin();
					#else				
						g_link_par[i].flag[IECLINK_YK_SND]=false;	
					#endif			
					pt->par_send_flag &= ~(1<<i);
				}	
				//主站遥控
				else
				{
					//dat[num++]=g_link_par[i].data[IECLINK_YK_SND].v;	
					len = get_par_link_101_to_104(&dat[num],&g_link_par[i].data[IECLINK_YK_SND].buf[0],g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].ti_m);
					num += len;					
					rt_printf("主站下发遥参定值\r\n");
					lnk_104_call(pt,g_link_par[i].data[IECLINK_YK_SND].ti_m,g_link_par[i].data[IECLINK_YK_SND].vsq,g_link_par[i].data[IECLINK_YK_SND].cot,dat,num);
					
					// 清除标志 
					#ifdef FUNC_MORE_PREREAD	
						pt->dtpartime[i]=ustimer_get_origin();
					#else				
						g_link_par[i].flag[IECLINK_YK_SND]=false;	
					#endif
					pt->par_send_flag &= ~(1<<i);
				}

				ptlnk->bMSend=true;
				break;
			}
		}
	}
#ifdef YPARA_LINK
	//遥参
	else if(get_queue_count(&pt->par_queue.queue) > 0)
	{	
		u8 dat[256];
		int i=0,num=0;
		msg_data_struct	*msg_data =&pt->temp_par;						
		get_data_queque(&pt->par_queue.queue,(u8 *)msg_data);

		
		//rt_printf("-----104级联:::遥参下发\r\n");
		//print_msg_base(ypara_msg);
		
		
		if(msg_data->type == modify_set)
		{				
			msg_ypara_data_struct	*ypara_msg = &msg_data->ypara_msg;
			/*定值区*/
			dat[num++] = (u8)ypara_msg->section_p;
			dat[num++] = (u8)(ypara_msg->section_p>>8);
			
			if(ypara_msg->cmd == YP_SEL)
			{				
				dat[num++] = 0x80; /*特征码*/
				for(i=0;i<ypara_msg->num;i++)
				{
					dat[num++]=(u8)ypara_msg->base_data[i].cp_s;
					dat[num++]=(u8)(ypara_msg->base_data[i].cp_s>>8);
					dat[num++]=0;
					dat[num++] = ypara_msg->base_data[i].val_iec.tag;
					dat[num++] = ypara_msg->base_data[i].val_iec.size;					
					if(ypara_msg->base_data[i].val_iec.size >0)
					{						
						memcpy(&dat[num],ypara_msg->base_data[i].val_iec.value,ypara_msg->base_data[i].val_iec.size); 				
						num += ypara_msg->base_data[i].val_iec.size; 						
					}					
				}	
			}
			else if(ypara_msg->cmd == YP_EXE)
			{				
				dat[num++] = 0; /*特征码*/			
				set_read_all(pt);
			}	
			else
			{			
				dat[num++] = 0x40; /*特征码*/
			}

			
			if((ypara_msg->cmd == 2) || (ypara_msg->cmd == 1))
			{				
				lnk_104_call(pt,203,ypara_msg->num,6,dat,num);
			}
			else
			{		
				lnk_104_call(pt,203,ypara_msg->num,8,dat,num);
			}

 			pt->sport	= msg_data->sport;
			ptlnk->bMSend=true; 	
			
		}
		else if(msg_data->type == settion_swht)
		{
			msg_oper_setion_struct *setion_msg = &msg_data->setion_msg;
			/*信息体地址0*/			
			dat[num++] = 0;
			dat[num++] = 0;
			dat[num++] = 0;
		
			/*定值区*/
			dat[num++] = (u8)setion_msg->section_p;
			dat[num++] = (u8)(setion_msg->section_p>>8);
					
			lnk_104_call(pt,200,1,6,dat,num);	
			pt->sport	= msg_data->sport;
			ptlnk->bMSend=true; 
		}	
	}
	else if(ptlnk->bSet_all)
	{
		u8 dat[4];
		int num=0;
		dat[num++]=0;	//当前定值区
		dat[num++]=0;	//当前定值区		
		lnk_104_call(pt,202,0,6,dat,num);	
		clear_read_all(pt);
		ptlnk->bMSend=true; 
	}
	// 空闲时，以500ms间隔召二级数据
#endif
#ifdef	RCD_STRAN_M
	else if((ptlnk->bRcd) && (ptlnk->bRcding == false)
		&& (get_queue_count(&pt->rcd_m.queue) <= 0) && (pt->tft.bTransing == false)
		&& (tRunPara.b_lb_master || (pt->b_lb_master)))		/*没有文件传输*/
	{
		u8 dat[4];
		int num=0;
	
		dat[num++]=0;
		dat[num++]=0;
		lnk_104_call(pt,IECLINK_RCD,1,6,dat,num);
		ptlnk->bMSend=true;	

		ptlnk->bRcding = true;
		ptlnk->dRcdingTime = ustimer_get_origin();			
		ptlnk->bRcd=false;	
	}
#endif
	// 空闲时，以500ms间隔召二级数据
	else if(lnk_file_check_trans(pt))
	{
		lnk_test_file_trans(pt);
	}

	// 子站测试帧应答
	if(pt->bTestAck)
	{
		lnk_104_ack(pt,FRAME_U_TEST_ACK);
		pt->bTestAck = false;
	}
	
	// 发送S帧
	if(((pt->RecvNum.ss - pt->AckRecvNum) >=tRunPara.w104W) 
			||((pt->bSendS ==2) || ((pt->bSendS == 1) && (dTCounter-ptlnk->dTInteral > 5*T_1s)))
	  )
	{
		lnk_104_sAck(pt);		
		pt->bSendS = 0;
	}	
}

void lnk_104_par_timer(IECLINK_DEF *pt)
{
	int i=0;
	int flag=0;
	
	for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
	{
		flag = pt->par_send_flag & (1<<i);
		if(g_link_par[i].flag[IECLINK_YK_SND] && !flag) 	
		{		
			if(ustimer_get_duration(pt->dtpartime[i]) > 10*USTIMER_SEC)	/*10秒遥参*/
			{
				rt_printf("--------遥参超时!!!\r\n");
				g_link_par[i].flag[IECLINK_YK_SND] = false;			
			}			
		}
	}
}



void lnk_104_app_timer(int net)
{
	IECLINK_DEF *pt = &g_link_104[net];
	LNK_STATUS *ptlnk=&pt->tlnk;
	if(!ptlnk->bCallAll)
	{
		if(dTCounter-ptlnk->dTCallAllTime>pt->callalltime)	//	10分钟总召一次
		{
			ptlnk->bCallAll=true;		
			ptlnk->dTCallAllTime=dTCounter;
		}
	}
	
#ifdef FUNC_MORE_PREREAD
	//lnk_104_par_timer(pt);	
#endif

#ifdef	RCD_STRAN_M
	if(ustimer_get_duration(ptlnk->dTRcdTime) > 1*USTIMER_SEC)	/*10秒间隔*/
	{
		ptlnk->bRcd = true; 	
		ptlnk->dTRcdTime=ustimer_get_origin();		
	}

	if(ptlnk->bRcding)
	{
		u8 tmp[64];
		
		if(ustimer_get_duration(ptlnk->dRcdingTime)>(10*USTIMER_SEC))	/*10秒无文件内容,超时*/
		{
			sprintf(tmp,"link[%d]::查询录波应答超时!!!!!!!",pt->chnl+1);
			log_str_time(LOG_OPERATE,tmp,0,1);		
			ptlnk->bRcding = false;
		}
	}

	if(pt->tft.bTransing)
	{
		u8 tmp1[128];
		
		if(ustimer_get_duration(pt->tft.us0_file_trans)>(10*USTIMER_SEC))	/*10秒无文件内容,超时*/
		{			
			sprintf(tmp1, "BAY%02d%s读文件传输超时(%d)!!!!!!!", pt->chnl+1,pt->tft.filename+5,pt->tft.offset);	/*104替换成级联通道号*/
			log_str_time(LOG_OPERATE,tmp1,0,1); 		
			pt->tft.bTransing=false;
		}
	}	
#endif
	
	// 检查对时间隔
	if(ustimer_get_duration(ptlnk->us0_set_time) > 5*60*USTIMER_SEC)
	{
		ptlnk->bSetTime = true;
	}

	// 检查测试帧超时
	if(pt->bStartTest)//启动了
	{
		if(ustimer_get_duration(pt->us0_test_wait)>(tRunPara.w104AckTime*USTIMER_SEC))
		{
			// 测试帧没有及时返回，主动关闭连接
			rt_printf_time("级联104(%d) 测试帧超时!\r\n",net);
			net_104link_close(net);
			return;
		}
	}
	else if(ustimer_get_duration(pt->us0_test) > (tRunPara.w104TestTime*USTIMER_SEC))//超时测试
	{
		// 发送测试帧
		lnk_104_ack(pt,FRAME_U_TEST);
		pt->us0_test=ustimer_get_origin();
		pt->us0_test_wait=ustimer_get_origin();
		pt->bStartTest=true;
	}

}


void lnk_104_app(int net)
{

	//通道未建立连接,直接返回
	if(!net_104link_is_connect(net))  
	{
		return;
	}

	// 如果没有初始化，初始化
	if(g_link104_init_ok[net] == 0)
	{
		lnk_104_init(net);
		g_link104_init_ok[net] = 1;
	}

	lnk_104_app_recv(net);
	lnk_104_app_send(net);
	lnk_104_app_timer(net);	
}

static void _lnk_104_recv_reset(IECLINK_DEF *pt)
{
	pt->nTypeCounter=0;
	pt->nRecvCnt=0;
}
 
void  lnk_104_recv(int net,u8 cRcvData) 
{
	IECLINK_DEF *pt = &g_link_104[net];
	pt->recvbuf[pt->nRecvCnt++]=cRcvData;	
	switch(pt->nTypeCounter)
	{
	case 0:
		if( cRcvData==0x68)
		{
			pt->nTypeCounter=1;
		}
		else
		{
			_lnk_104_recv_reset(pt);
		}
		break;
	case 1:
			pt->nRecvLenth=cRcvData+2;
			pt->nTypeCounter=2;
		break;
		
	case 2:
		if(pt->nRecvCnt>=pt->nRecvLenth)	/*报文接受完毕*/
		{
			_lnk_104_recv_reset(pt);
			pt->bData=true;
			g_net_104link_data[net]=1;
			// 唤醒主循环
			mainloop_wakeup();
		}
		break;
	default:		
		_lnk_104_recv_reset(pt);
		break;
	}
}



int  lnk_info_printf(void)
{
	int i;

	rt_printf("级联遥控信息:\n");
	rt_printf("cp_m\tcp_s\tflg[0]\tflg[1]\tflg[2]\r\n");
	for(i=0; i<SWITCH_NUM_EXT_PUB; i++)
	{
		LINKYK_DEF * yk;
		yk = &g_lnk_yk[i];
		rt_printf("%04x\t%04x\t%d\t%d\t%d\r\n",yk->cp_m,yk->cp_s,yk->flag[0],yk->flag[1],yk->flag[2]);
	}
	
	return 0;
}



/*********下面是文件传输，模拟主站程序，招目录后，招第一个文件******************/

void  lnk_read_test_file(void)
{
	int	i;

	for(i=0; i<CFG_LINK_101_NUM; i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_PH_M)
		{
			((IECLINK_DEF *)g_tRsComm[i].ptBuf)->tft.bDir = true;
		}
	}

	for(i=0; i<CFG_LINK_104_NUM; i++)
	{
		g_link_104[i].tft.bDir= true;
	}


	
}
void  lnk_write_test_file(void)
{
	int	i;

	for(i=0; i<CFG_LINK_101_NUM; i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[i].wProtocol == PROTOCOL_101_PH_M)
		{
			((IECLINK_DEF *)g_tRsComm[i].ptBuf)->tft.bUpdateStart = true;
		}
	}

	for(i=0; i<CFG_LINK_104_NUM; i++)
	{
		g_link_104[i].tft.bUpdateStart= true;
	}

	
}

bool lnk_file_check_trans(IECLINK_DEF *pt)
{
	bool ret;
	ret=pt->tft.bDir||pt->tft.bFile||pt->tft.bFileok||pt->tft.bwFile||pt->tft.bwTrans||pt->tft.b104ack||pt->tft.bUpdateStart||pt->tft.bUpdateEnd;
	return ret;
}

void lnk_test_file_trans(IECLINK_DEF *pt)
{
	char * strdir="/app/data/filetest/";
	u8 dirlen;	
	
	dirlen=strlen(strdir);
	if(pt->tft.bDir)  //招目录
	{
		u8 dat[128];
		int num=0;
		dat[num++]=0; // 信息体地址
		dat[num++]=0;	
		if(pt->type==IEC104_CHN)dat[num++]=0;	
		dat[num++]=2; // 附加数据包类型

		dat[num++]=1; // 读目录
		dat[num++]=0; // ID
		dat[num++]=0;
		dat[num++]=0;
		dat[num++]=0;
		
		dat[num++]=dirlen;
		memcpy(&dat[num],strdir,dirlen);
		num+=dirlen;
		dat[num++]=0; // 召唤标识 :0 全部 :1 时间范围内

	// 起始时间
		dat[num++]=0;				//MsL
		dat[num++]=0;				//MsH
		dat[num++]=0;				//Min
		dat[num++]=0;				//hour
		dat[num++]=1;	//Day
		dat[num++]=1;				//month
		dat[num++]=17;				//year

	// 结束时间
		dat[num++]=0;				//MsL
		dat[num++]=0;				//MsH
		dat[num++]=10;				//Min
		dat[num++]=15;				//hour
		dat[num++]=21;	//Day
		dat[num++]=2;				//month
		dat[num++]=17;				//year
		if(pt->type==IEC101_CHN)
		{		
			lnk_101_call(pt,210,1,5,dat,num);
		}
		else
		{
			lnk_104_call(pt,210,1,5,dat,num);
		}
		pt->tft.bDir=false;
	}

	if(pt->tft.bFile)  //召文件
	{
		u8 dat[128];
		int num=0;
		dat[num++]=0; // 信息体地址
		dat[num++]=0;		
		if(pt->type==IEC104_CHN)dat[num++]=0;
		dat[num++]=2; // 附加数据包类型
		dat[num++]=3; // 读文件
		dat[num++]=pt->tft.fnamelen;
		memcpy(&dat[num],pt->tft.filename,pt->tft.fnamelen);
		num+=pt->tft.fnamelen;
		if(pt->type==IEC101_CHN)
		{		
			lnk_101_call(pt,210,1,5,dat,num);
		}
		else
		{
			lnk_104_call(pt,210,1,5,dat,num);
		}
		pt->tft.bFile=false;		
	}

	if(pt->tft.bFileok)  //文件传输确认
	{
		u8 dat[128];
		int num=0;
		dat[num++]=0; // 信息体地址
		dat[num++]=0;		
		if(pt->type==IEC104_CHN)dat[num++]=0;	
		dat[num++]=2; // 附加数据包类型
		dat[num++]=6; // 读文件
		dat[num++]=(u8)pt->tft.fileid; // ID
		dat[num++]=(u8)(pt->tft.fileid>>8);
		dat[num++]=(u8)(pt->tft.fileid>>16);
		dat[num++]=(u8)(pt->tft.fileid>>24);
		
		dat[num++]=(u8)pt->tft.offset; // 偏移
		dat[num++]=(u8)(pt->tft.offset>>8);
		dat[num++]=(u8)(pt->tft.offset>>16);
		dat[num++]=(u8)(pt->tft.offset>>24);
		dat[num++]=(pt->tft.offset+FILE_SEND_FRAME_LENTH)>=pt->tft.filelenth?0:1; // 有无后续
		if(pt->type==IEC101_CHN)
		{		
			lnk_101_call(pt,210,1,6,dat,num);
		}
		else
		{
			lnk_104_call(pt,210,1,6,dat,num);
		}
		pt->tft.bFileok=false;
	}

	if(pt->tft.bwFile)  // 写文件
	{
		u8 dat[128];
		int num=0;
	#if defined(CPU_AM335X)	
		char* ko_path ="/app/data/335x_dftu.ko";
		char *filename="335x_dftu.ko";
	#else
		char* ko_path ="/app/data/dftu.ko"; 	
		char *filename="dftu.ko";
	#endif
		int namelen=strlen(filename);
		struct file *handle;
		loff_t pos;
		int ret;
		handle= rt_file_open(ko_path,O_RDONLY ,0);
		if(IS_ERR(handle))
		{
			rt_printf("打开%s,失败",ko_path);
			pt->tft.bwFile=false;		
			return;
		}

		//得到文件长度
		pt->tft.wfilelenth = rt_file_getfile_size(handle);
		if(pt->tft.wfilelenth == 0)
		{
			rt_file_close(handle,0);
			return;
		}

				//分配内存
		pt->tft.wbuf = rt_malloc(pt->tft.wfilelenth);
		if(pt->tft.wbuf == NULL)
		{
			pt->tft.bwFile=false;		
			rt_printf("%s: 分配内存失败\r\n",__func__);
			return;
		}
		 //读出文件内容
		pos=0;
		ret = rt_file_read(handle,pt->tft.wbuf, pt->tft.wfilelenth,&pos);
		if(ret !=  pt->tft.wfilelenth) 
		{
			rt_file_close(handle,0);		
			rt_printf("%s: read error:file_length=%d,ret=%d!\r\n",__func__,pt->tft.wfilelenth,ret);

			pt->tft.bwFile=false;		
			rt_free(pt->tft.wbuf);
			return ;
		}
		pt->tft.wId=0x1234;
		dat[num++]=0; // 信息体地址
		dat[num++]=0;		
		if(pt->type==IEC104_CHN)dat[num++]=0;	
		dat[num++]=2; // 附加数据包类型
		dat[num++]=7; // 读文件
		dat[num++]=namelen;
		memcpy(&dat[num],filename,namelen);
		num+=namelen;
		dat[num++]=(u8)pt->tft.wId; // ID
		dat[num++]=(u8)(pt->tft.wId>>8);
		dat[num++]=(u8)(pt->tft.wId>>16);
		dat[num++]=(u8)(pt->tft.wId>>24);
		dat[num++]=(u8)pt->tft.wfilelenth; // ID
		dat[num++]=(u8)(pt->tft.wfilelenth>>8);
		dat[num++]=(u8)(pt->tft.wfilelenth>>16);
		dat[num++]=(u8)(pt->tft.wfilelenth>>24);		

		if(pt->type==IEC101_CHN)
		{		
			lnk_101_call(pt,210,1,6,dat,num);
		}
		else
		{
			lnk_104_call(pt,210,1,6,dat,num);
		}		
		pt->tft.bwFile=false;	
		pt->tft.woffset=0;
		rt_printf("%s:malloc:file_length=%d,ret=%d!\r\n",__func__,pt->tft.wfilelenth,ret);
	}

	if(pt->tft.bwTrans)  // 写文件
	{
		u8 dat[256];
		int num=0;
		int i;
		BYTE datalen=FILE_SEND_FRAME_LENTH;
		bool beof=false;
		BYTE checksum=0;
		static u32 us0_1=0;

		 if((ustimer_get_duration(us0_1) <USTIMER_MS*6))//超时测试
		 {
			return;
		 }
		us0_1=ustimer_get_origin();
		if((pt->tft.woffset+FILE_SEND_FRAME_LENTH)>=pt->tft.wfilelenth)
		{
			datalen=pt->tft.wfilelenth-pt->tft.woffset;  //最后一帧传输的字节数
			beof=true;
			pt->tft.bwTrans=false;
		}
		dat[num++]=0; // 信息体地址
		dat[num++]=0;		
		if(pt->type==IEC104_CHN)dat[num++]=0;	
		dat[num++]=2; // 附加数据包类型
		dat[num++]=9; // 写文件
		dat[num++]=(u8)pt->tft.wId; // ID
		dat[num++]=(u8)(pt->tft.wId>>8);
		dat[num++]=(u8)(pt->tft.wId>>16);
		dat[num++]=(u8)(pt->tft.wId>>24);
		
		dat[num++]=(u8)pt->tft.woffset; // 偏移
		dat[num++]=(u8)(pt->tft.woffset>>8);
		dat[num++]=(u8)(pt->tft.woffset>>16);
		dat[num++]=(u8)(pt->tft.woffset>>24);
		dat[num++]=beof?0:1; // 有无后续
		for(i=0;i<datalen;i++)
		{
			BYTE dd;
			dd=pt->tft.wbuf[pt->tft.woffset+i];
			dat[num++] = dd;
			checksum+=dd;
		}
		dat[num++]=checksum;		

		if(pt->type==IEC101_CHN)
		{		
			lnk_101_call(pt,210,1,5,dat,num);
		}
		else
		{
			lnk_104_call(pt,210,1,5,dat,num);
		}		
		if(beof)
		{
			if(!pt->tft.wbuf)
			{
				rt_free(pt->tft.wbuf);
				pt->tft.wbuf=NULL;
			}
			rt_printf("%s:写文件传输完毕，释放内存",__func__);
		}
		if(pt->type==IEC101_CHN)
		{
			pt->tft.bwTrans=false;
		}
		if(pt->type==IEC104_CHN)
		{
			pt->tft.woffset+=FILE_SEND_FRAME_LENTH;
			if(pt->tft.woffset>=pt->tft.wfilelenth)
			{
				pt->tft.bwTrans=false;
			}			
		}	
		
	}
	if(pt->tft.bUpdateStart)  //文件升级启动
	{
		u8 dat[128];
		int num=0;
		dat[num++]=0; // 信息体地址
		dat[num++]=0;		
		if(pt->type==IEC104_CHN)dat[num++]=0;	
		dat[num++]=0x80; // ctype
		if(pt->type==IEC101_CHN)
		{		
			lnk_101_call(pt,211,1,6,dat,num);
		}
		else
		{
			lnk_104_call(pt,211,1,6,dat,num);
		}
		pt->tft.bUpdateStart=false;
	}

	if(pt->tft.bUpdateEnd)  //文件升级结束
	{
		u8 dat[128];
		int num=0;
		dat[num++]=0; // 信息体地址
		dat[num++]=0;		
		if(pt->type==IEC104_CHN)dat[num++]=0;	
		dat[num++]=0x00; // ctype
		if(pt->type==IEC101_CHN)
		{		
			lnk_101_call(pt,211,1,6,dat,num);
		}
		else
		{
			lnk_104_call(pt,211,1,6,dat,num);
		}
		pt->tft.bUpdateEnd=false;
	}


	if(pt->tft.b104ack)
	{
		lnk_104_sAck(pt);
		pt->tft.b104ack=false;
	}
	
}
void lnk_test_file_frame(IECLINK_DEF *pt,u8 *pdat,u8 framelen) //  
{
	u8 cmd ,*pd;
	int i;	
#ifdef RCD_STRAN_M
	s32 ret=0;
	char tmp[128],tmp1[128];
	static s32 testnum=0;

	struct dir_file_ext_struct *pdfs;
	struct dir_file_ext_struct *pdfs_min=0;
	int file_cnt = 0;
	u8 flag=0;
#endif
	
	pdat+=1; 
	cmd=pdat[0];
	if(cmd==1) // 目录
	{
		rt_printf("\r\n 收到目录 成功标识:%d ID:%d 后续标识:%d  文件数量:%d\r\n",pdat[1],(pdat[2]|(pdat[3]<<8)|(pdat[4]<<16)|(pdat[5]<<24)),pdat[6],pdat[7]);
		pd=&pdat[8];
		for(i=0;i<pdat[7];i++)  //文件
		{
			u8 namestr[64],namelen;
			u32 filelen;
			namelen=pd[0];
			if(namelen>63)
			{
				rt_printf("\r\n文件长度错误!");
				break;
			}
			memcpy(namestr,&pd[1],namelen);
			namestr[namelen]='\0';
			pd+=namelen+2;
			filelen=(pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24));
			pd+=4;
			rt_printf("\r\n 文件名长度:%d 名称:%s  长度:%d 时间:%d-%d-%d %d:%d:%d.%d\r\n",namelen,namestr,filelen,pd[6],pd[5],pd[4],pd[3],pd[2],(pd[1]*256+pd[0])/1000,(pd[1]*256+pd[0])%1000);
			pd+=7;	

			if(i==0)
			{
				pt->tft.filelenth=filelen;
				pt->tft.fnamelen=namelen;
				memcpy(pt->tft.filename,namestr,namelen);
				pt->tft.bFile=true;
			}
		}	
	}

	if(cmd==4) // 读文件激活
	{
			u8 namestr[64],namelen;
			u32 id,filelen;
			pd=&pdat[2];
			namelen=pd[0];
			if(namelen>63)
			{
				rt_printf("\r\n文件长度错误!");
				return;
			}
			memcpy(namestr,&pd[1],namelen);
			namestr[namelen]='\0';
			pd+=namelen+1;
			id=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24);
			pd+=4;
			filelen=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24);
			rt_printf("\r\n 文件名长度:%d 名称:%s  长度:%d id:%d\r\n",namelen,namestr,filelen,id);
			//pt->tft.bFile=true;
			{
				if(pt->type==IEC104_CHN)
				{
					char fnstr[64];
					sprintf(fnstr,"/tmp/rmtfile_%d",pt->chnl);
					pt->tft.handle = rt_file_open(fnstr,O_CREAT|O_RDWR|O_TRUNC,0);
					if(IS_ERR(pt->tft.handle))
					{ 
						pt->tft.handle = 0;
						rt_printf("%s创建失败!\r\n",fnstr);
						pt->tft.bFile=false;
						return ; 
					}													
				}
				else
				{
					//创建文件
					char *fnstr="/app/data/rmtfile";
					pt->tft.handle = rt_file_open(fnstr,O_CREAT|O_RDWR|O_TRUNC,0);
					if(IS_ERR(pt->tft.handle))
					{ 
						pt->tft.handle = 0;
						rt_printf("%s创建失败!\r\n",fnstr);
						pt->tft.bFile=false;
						return ; 
					} 
			
				}				
			}
			pt->tft.fileid=id;
			pt->tft.filelenth=filelen;			
			pt->tft.us0_file_trans = ustimer_get_origin();
	}
	if(cmd==5) // 读文件响应
	{
		loff_t pos;
		u32 id,offset;
		pd=&pdat[1];
		id=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24);
		pd+=4;
		offset=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24);
#ifdef	RCD_STRAN_M	
		pd+=4;
		flag = *pd++;	/*结束标识*/	
		pos=offset;
		if(pt->tft.bTransing == false) return;	
		
		rt_file_write(pt->tft.handle,pd,framelen-11,&pos);
		if(flag == 0)
		{				
			rt_file_close(pt->tft.handle,0);			
			if(strncmp(pt->tft.filename,"BAY",3) == 0)	/*录波文件*/
			{					
				if(pt->type==IEC104_CHN)
				{
					sprintf(pt->tft.filename, "BAY%02d%s", pt->chnl+1,pt->tft.filename+5);	/*104替换成级联通道号*/															
				}			
				sprintf(tmp, "%s传输完成!!!",pt->tft.filename); 
				log_str_time(LOG_OPERATE,tmp,0,1); 
				

				sprintf(tmp, "%s%s", HF_WAVE_DIR,pt->tft.filename); 
				if(pt->type==IEC104_CHN)
				{
					sprintf(tmp1,"/tmp/rmtfile_%d",pt->chnl);				
					ret = rt_file_mv(tmp1, tmp);					
				}
				else
				{				
					ret = rt_file_mv("/app/data/rmtfile", tmp);
				}				
				
				if(ret != 0)
				{
					rt_printf("%s 文件移动失败(ret=%d)!\r\n","/app/data/rmtfile",ret);
					rt_file_del("/app/data/rmtfile");
				}
				
				
				sprintf(tmp, "/tmp/dev_rcd_%d",(int)testnum++); 	
				pdfs = hf_get_dir_file_ext(HF_WAVE_DIR, &file_cnt, tmp);
				if((file_cnt) > (NEWRCD_COUNT_M*2)*2)
				{
					rt_printf("file_cnt=%d***********************************\r\n",file_cnt);
					//找到最早的文件，并删除
					pdfs_min = pdfs;
					for(i=1;i<file_cnt;i++)
					{
						if(strncmp(pdfs[i].file_name+11, pdfs_min->file_name+11, 19) < 0)
						{
							pdfs_min	= &pdfs[i];
						}
					}	

					//因为文件以及已经排好序，找到第一个是cfg文件，第二个是dat文件
					//先删除.cfg文件
					sprintf(tmp, "%s%s", HF_WAVE_DIR,pdfs_min->file_name);	
					rt_file_del(tmp);
					
					sprintf(tmp, "%s%s", HF_WAVE_DIR,pdfs_min[1].file_name);	
					rt_file_del(tmp);
				}
				
				if(pdfs)
				{
					rt_free(pdfs);
				}
			}

			pt->tft.bTransing =false;		
			pt->tft.bFileok=false;
			pt->tft.offset=offset;			
		}
		else
		{	
			if(pt->type==IEC104_CHN)	pt->tft.b104ack=true;
			pt->tft.us0_file_trans = ustimer_get_origin();
		}
#else
		pd+=5;
		pos=offset;
		rt_file_write(pt->tft.handle,pd,framelen-11,&pos);
		if(offset+FILE_SEND_FRAME_LENTH>=pt->tft.filelenth)
		{
			rt_file_close(pt->tft.handle,0);			
			rt_printf("文件传输完毕!\r\n");
			pt->tft.bFileok=true;
			pt->tft.offset=offset;
		}
		else if(pt->type==IEC101_CHN)
		{
			pt->tft.bFileok=true;
			pt->tft.offset=offset;

		}
		else if(pt->type==IEC104_CHN)
		{
			pt->tft.b104ack=true;
		}
#endif
	}
	
	if(cmd==8) //写文件激活
	{
		pt->tft.bwTrans=true;
		pt->tft.woffset=0;
	}

	if(cmd==10) //写文件确认
	{
		u32 id,offset;
		pd=&pdat[1];
		id=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24);
		pd+=4;
		offset=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24);
		pd+=5;
		pt->tft.bwTrans=true;		
		pt->tft.woffset=offset+FILE_SEND_FRAME_LENTH;

		if(pt->tft.woffset>=pt->tft.wfilelenth)
		{
			pt->tft.bwTrans=false;
			if(pdat[9]==0)
			{
				pt->tft.bUpdateEnd=true;
			}

		}
	}	
}

void lnk_update_file_frame(IECLINK_DEF *pt,u8 ctype) //  
{
	if(ctype&0x80) // 目录
	{
		pt->tft.bwFile=true; 
	}	
}




/************************endfile**********************/



