/********************************************************************
版权所有： 
文件版本： V1.00
文件名称： Modbus.c
生成日期： 2008年11月13日
作    者：xxxxxx
使用范围：

功    能： Modbus规约处理，为节省RAM空间，MODBUS规约处理，借用了103规约的结构定义
更新信息：
更新日志1：
修改者:
修改日期:
修改内容:
修改原因:
*********************************************************************/


#include "head.h"

struct MODBUS_CMD_LEN
{
	u8	cmd;
	u8    len;
}; // 16*2
 
struct MODBUS_CMD_LEN tModbusCmd[]=
{
	{0x01,0},
	{0x02,0},
	{0x03,0},
	{0x04,0},
	{0x05,4},
	{0x06,4},
	{0x07,1},
	{0x0b,1},
	{0x0c,0},
	{0x0F,4},
	{0x10,4},
	{0x11,0},
	{0x85,1},
};
int modbus_cmd_num=sizeof(tModbusCmd)/sizeof(tModbusCmd[0]);

BYTE  MoDusCRCtableHi[] =   // Modbus 高位校验码
{
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40
} ;

//-------------------------------------------------------------

//@@***********************************************************

//                MoDus CRC 低位字节值表

//@@***********************************************************

//-------------------------------------------------------------

BYTE  MoDusCRCtableLo[] = 
{
	0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04,
	0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8,
	0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,
	0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10,
	0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,
	0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38,
	0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,
	0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,
	0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,
	0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,
	0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,
	0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,
	0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,
	0x9C,0x5C,0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98,
	0x88,0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C,
	0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40
} ;

/**************************************************************************
函数名称：Modbus_CRC16
函数版本：1.00 
作者：   
创建日期：2008.11.15     
函数功能说明：Modbus规约的CRC校验
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/

WORD Modbus_CRC16(BYTE *inbytes, WORD CRCnumber)  // 返回，低字节在高位

{

         BYTE crcbyteHi = 0xFF ;                                     

         BYTE crcbyteLo = 0xFF ;                                     

         BYTE uIndex ;                                               

         

         while (CRCnumber--)                                          

         {

                   uIndex = crcbyteHi ^ *inbytes++ ;                          

                   crcbyteHi = crcbyteLo ^ MoDusCRCtableHi[uIndex] ;                   

                   crcbyteLo = MoDusCRCtableLo[uIndex] ;                            

         }

         return ( (crcbyteHi << 8) | crcbyteLo ) ;                                         

}

int  _getslaveaddr(char *buf)
{
	char *str,str1[6];
	int val=0;
	str=strstr(buf,"_slave");
	if(str)
	{
		memcpy(str1,&str[6],2);
		str1[2]='\0';
		val=strtoul(str1,NULL,10);
	}
	return val;
}

static void _getmodbusinf(MODBUS_DEF *pt,u8 *filestr)
{
	u8 str[64];
	if(filestr[0]=='[') // 是规约类型
	{
		pt->bcfg=false;
		sprintf(str,"[COM%d_MODBUS]",pt->chnl);
		if(strcmp(filestr,"[MODBUS_ALL]")==0||strcmp(filestr,str)==0)
		{
			pt->bcfg=true;
		}
		return;
	}
	if(!pt->bcfg)return;
	if(strstr(filestr,"yxcmd")) // 遥信命令码
	{
		pt->yxcmd=getstrval(filestr);
	}
	else if(strstr(filestr,"yccmd")) // 
	{
		pt->yccmd=getstrval(filestr);
	}
	else if(strstr(filestr,"ykcmd")) // 
	{
		pt->ykcmd=getstrval(filestr);
	}
	else if(strstr(filestr,"ddcmd")) // 
	{
		pt->ddcmd=getstrval(filestr);
	}
	else if(strstr(filestr,"yxreadbit")) // 
	{
		pt->readbit=getstrval(filestr);
	}
	else if(strstr(filestr,"yxbytes")) // 
	{
		pt->yxbitbytes=getstrval(filestr);
	}
	else if(strstr(filestr,"ycbytes")) // 
	{
		pt->ycbitbytes=getstrval(filestr);
	}
	else if(strstr(filestr,"ykbytes")) //
	{
		pt->ykbitbytes=getstrval(filestr);
	}
	else if(strstr(filestr,"ddbytes")) //
	{
		pt->ddbitbytes=getstrval(filestr);
	}
	else if(strstr(filestr,"ykval_h")) // 
	{
		pt->ykval_h=getstrval(filestr);
	}
	else if(strstr(filestr,"ykval_f")) // 
	{
		pt->ykval_f=getstrval(filestr);
	}
	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,"coiladdr")) // 
	{
		pt->coiladdr=getstrval(filestr); // 线圈地址
	}	
	else if(strstr(filestr,"cmd_dinum")) // 
	{
		pt->cmd_dinum=getstrval(filestr); // 点号长度
	}	
	else if(strstr(filestr,"cmd_datnum")) // 
	{
		pt->cmd_datnum=getstrval(filestr); // 数据长度
	}	
	else if(strstr(filestr,"dat_dir")) // 
	{
		pt->dat_dir=getstrval(filestr); //数据方向
	}	
	else if(strstr(filestr,"yxdi")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=((MODBUS_TYPE_YX<<4)|MODBUS_INF_DI);
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"ycdi")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=((MODBUS_TYPE_YC<<4)|MODBUS_INF_DI);
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"dddi")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=((MODBUS_TYPE_DD<<4)|MODBUS_INF_DI);
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"yxnum")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=((MODBUS_TYPE_YX<<4)|MODBUS_INF_NUM);
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"ycnum")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=((MODBUS_TYPE_YC<<4)|MODBUS_INF_NUM);
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"ddnum")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=((MODBUS_TYPE_DD<<4)|MODBUS_INF_NUM);
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"yxbit")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=((MODBUS_TYPE_YX<<4)|MODBUS_INF_BITS);
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"sendaddr")) // 
	{
		pt->tinf[pt->infnum].slaveaddr=_getslaveaddr(filestr);
		pt->tinf[pt->infnum].val=getstrval(filestr);
		pt->tinf[pt->infnum].type=MODBUS_INF_SENDADDR;
		pt->infnum++;
		if(pt->infnum>=MODBUS_INF_MAX)pt->infnum=MODBUS_INF_MAX-1;
	}
	else if(strstr(filestr,"ycrate")) // 
	{
		pt->yc_rate=getstrval(filestr);
	}
#ifdef MODBUS_YX_REG_NUM
	else if(strstr(filestr,"yxregnum")) // 
	{
		pt->yxregnum=getstrval(filestr);
	}
#endif

	
}

static int  modbus_init_inf(MODBUS_DEF *pt)
{
	u32 i,file_length;
	struct file * pfile;
	u8 *filebuf;
	u8  filestr[128],*pstr,strlenth;
	loff_t pos;
	// 打开文件
	pfile = rt_file_open("/app/data/pcolcfg.ini",O_RDONLY ,0);
	if(IS_ERR(pfile))
	{
		dp_err_n_c_rt("error! 无法打开 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';
			_getmodbusinf(pt,filestr);
			pstr=filestr;
			strlenth=0;
		}
	}
	rt_file_close(pfile,0);	// 关闭文件
	rt_free(filebuf);			// 释放内存
	return 0;
}

typedef struct MODBUS_SLAVE_DEF
{
	u8 cmd;
	u8 type;
	u8 dinum;	
	u8 bitbytes;
	u8 readbit;
#ifdef MODBUS_YX_REG_NUM
	u8 yxregnum;
#endif
	WORD dimin;
	WORD dimax;
	WORD slaveaddr;
	

}MODBUS_SLAVE_DEF;

void modbus_count_slaveaddr(MODBUS_DEF *pt,u8 chnl,LINK_TABLE* lt,u32 num,BYTE cmd,BYTE bitbytes,BYTE readbit,BYTE type)
{
	u8 ch;
	u8 addr=0;
	u16 di;
	MODBUS_SLAVE_DEF tms[32];
	int i,j,slavenum;
#ifdef MODBUS_YX_REG_NUM
	BYTE yxregnum = pt->yxregnum;
	WORD yx_dimin=0,yx_dimax=0;
#endif

	memset(&tms,0,sizeof(tms));
	slavenum=0;
	for(j=0;j<num;j++)	
	{
		ch=(u8)((lt->cp_s>>21)&0x0f);
		addr=(u8)((lt->cp_s>>16)&0x1f);
		di=(u16)lt->cp_s;		
		
		if(addr>0&&(ch==chnl)) // 通道相符
		{
			if(slavenum==0)
			{
				tms[slavenum].slaveaddr=addr;
				tms[slavenum].dimax=di;
				tms[slavenum].dimin=di;
				tms[slavenum].cmd=cmd;
				tms[slavenum].bitbytes=bitbytes;				
				tms[slavenum].readbit=readbit;				
				tms[slavenum].type=type;
				tms[slavenum].dinum=1;
			#ifdef MODBUS_YX_REG_NUM
				tms[slavenum].yxregnum=yxregnum;
			#endif
				slavenum++;
				
			}
			else
			{
				for(i=0;i<slavenum;i++)
				{
					if(tms[i].slaveaddr==addr&& (tms[i].type==type) )// 同一类型,同一子站地址
					{
						if(di<tms[i].dimin)
						{
							tms[i].dimin=di;
						}
						if(di>tms[i].dimax)
						{
							tms[i].dimax=di;
						}
						tms[i].dinum++; // 个数加1
						break;
					}
				}
				if(i==slavenum)
				{
					tms[slavenum].slaveaddr=addr;
					tms[slavenum].dimax=di;
					tms[slavenum].dimin=di;
					tms[slavenum].cmd=cmd;
					tms[slavenum].bitbytes=bitbytes;				
					tms[slavenum].readbit=readbit;				
					tms[slavenum].type=type;
					tms[slavenum].dinum=1;
				#ifdef MODBUS_YX_REG_NUM
					tms[slavenum].yxregnum=yxregnum;
				#endif
					slavenum++;
				}			
			}
		}
		lt++;
	}

	
	for(i=0;i<slavenum;i++)
	{
		WORD maxsmin;

		for(j=0;j<pt->infnum;j++)  // 判断字节数类型，是否有重新定义
		{
			if(tms[i].slaveaddr==pt->tinf[j].slaveaddr)
			{
		
				if(((pt->tinf[j].type>>4)&0x0f)==tms[i].type)
				{		
					if((pt->tinf[j].type&0x0f)==MODBUS_INF_BITS)
					{
						tms[i].readbit=pt->tinf[j].val;
					}
				}
			}
		}	
	#ifdef MODBUS_YX_REG_NUM
		yx_dimax = tms[i].dimax;
		yx_dimin = tms[i].dimin;
	#endif
		if(type==MODBUS_TYPE_YX && tms[i].readbit==1 && tms[i].dimin!=0) // 遥信且按bit取值
		{
		#ifndef LINK_MODBUS_YX_CP
			tms[i].dimax>>=4; // 最低4bit为 位序号
			tms[i].dimin>>=4; // 最低4bit为 位序号
		#endif
		}
		pt->tcmd[pt->cmdnum].slaveaddr=tms[i].slaveaddr;
		pt->tcmd[pt->cmdnum].cmd=tms[i].cmd;
		pt->tcmd[pt->cmdnum].bitbytes=tms[i].bitbytes;;		
		pt->tcmd[pt->cmdnum].readbit=tms[i].readbit;;		
		pt->tcmd[pt->cmdnum].di=tms[i].dimin;
		pt->tcmd[pt->cmdnum].type=tms[i].type;
		maxsmin=tms[i].dimax-tms[i].dimin+1;
	#ifdef MODBUS_YX_REG_NUM
		if((type==MODBUS_TYPE_YX&&tms[i].readbit==1))
		{
			if(tms[i].yxregnum==0)
			{
				pt->tcmd[pt->cmdnum].num=(yx_dimax-yx_dimin+1)%16?(yx_dimax-yx_dimin+1)/16+1:(yx_dimax-yx_dimin+1)/16;
			}
			else 
			{
				pt->tcmd[pt->cmdnum].num=yx_dimax-yx_dimin+1;
			}	
		}
		else 
		{
			pt->tcmd[pt->cmdnum].num=(maxsmin>tms[i].dinum)?maxsmin:tms[i].dinum;  //  取个数大的为寄存器个数
		}
	#else
		pt->tcmd[pt->cmdnum].num=(maxsmin>tms[i].dinum)?maxsmin:tms[i].dinum;  //  取个数大的为寄存器个数
	#endif
		pt->tcmd[pt->cmdnum].byxfirst=false;

		if(tms[i].bitbytes==4||tms[i].bitbytes==13) //  四个字节或浮点数
		{
			pt->tcmd[pt->cmdnum].num*=2;  // 寄存器个数加倍
		}		

		for(j=0;j<pt->infnum;j++)  // 更新重新定义的点号和召唤个数
		{
			if(pt->tcmd[pt->cmdnum].slaveaddr==pt->tinf[j].slaveaddr)
			{
		
				if(((pt->tinf[j].type>>4)&0x0f)==pt->tcmd[pt->cmdnum].type)
				{		
					if((pt->tinf[j].type&0x0f)==MODBUS_INF_DI)
					{
						pt->tcmd[pt->cmdnum].di=pt->tinf[j].val;
					}
					else if((pt->tinf[j].type&0x0f)==MODBUS_INF_NUM)
					{
						pt->tcmd[pt->cmdnum].num=pt->tinf[j].val;
					}
				}
			}
		}		
		pt->cmdnum++;
		if(pt->cmdnum>=MODBUS_CMD_NUM)
		{
			pt->cmdnum=MODBUS_CMD_NUM-1;
		}
	}
}

void modbus_sendaddr_init(MODBUS_DEF *pt)
{
	int i;
	for(i=0;i<pt->cmdnum;i++)
	{
		int j;
		pt->tcmd[i].sendaddr=pt->tcmd[i].slaveaddr;
		for(j=0;j<pt->infnum;j++)
		{
			if((pt->tinf[j].type==MODBUS_INF_SENDADDR)&&(pt->tinf[j].slaveaddr==pt->tcmd[i].slaveaddr))
			{
				pt->tcmd[i].sendaddr=pt->tinf[j].val;
			}
		}
	}
}
/**************************************************************************
函数名称：Modbus_Init
函数版本：1.00 
作者：   
创建日期：2008.9.1     
函数功能说明：Modbus规约初始化
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/

void modbus_Init(MODBUS_DEF *pt,BYTE chnl)
{
	int i;	
	memset(pt,0,sizeof(MODBUS_DEF));
	pt->type=IEC_MODBUS_M;
	pt->chnl=chnl;
	pt->bData=false;
	pt->sendbuf=g_tRsComm[chnl].sendbuf;
	pt->dsendtime=dTCounter;
	pt->yxcmd=2;
	pt->yccmd=3;
	pt->ykcmd=5;
	pt->ddcmd=4;
	pt->yxbitbytes=1;
	pt->ycbitbytes=2;
	pt->ykbitbytes=2;	
	pt->ddbitbytes=4;	
	pt->ykval_h=0xff00;
	pt->ykval_f=0x0000;
	pt->coiladdr=0;
	pt->readbit=0;
	pt->cmd_datnum=2;
	pt->cmd_dinum=2;
	pt->dat_dir=0;
	pt->yc_rate=1;
	modbus_init_inf(pt);
	modbus_count_slaveaddr(pt,chnl+2,&g_lt_di[0],g_lt_di_num,pt->yxcmd,pt->yxbitbytes,pt->readbit,MODBUS_TYPE_YX);
	modbus_count_slaveaddr(pt,chnl+2,&g_lt_ac[0],g_lt_ac_num,pt->yccmd,pt->ycbitbytes,0,MODBUS_TYPE_YC);
	modbus_count_slaveaddr(pt,chnl+2,&g_lt_dd[0],g_lt_dd_num,pt->ddcmd,pt->ddbitbytes,0,MODBUS_TYPE_DD);
	modbus_sendaddr_init(pt);
	rt_printf("\r\nmodbus_init(channel=%d):\r\n",chnl);
	for(i=0;i<pt->cmdnum;i++)
	{
		rt_printf("chnl=%d addr=%d sendaddr=%d di=%04x cmd=%d num=%d type=%d bitbytes=%d readbit=%d\r\n",chnl,pt->tcmd[i].slaveaddr,pt->tcmd[i].sendaddr,pt->tcmd[i].di,pt->tcmd[i].cmd,pt->tcmd[i].num,pt->tcmd[i].type,pt->tcmd[i].bitbytes,pt->tcmd[i].readbit);
	}
	
}

/**************************************************************************
函数名称：Modbus_Recv_Rst
函数版本：1.00 
作者：   
创建日期：2008.11.15     
函数功能说明：复归数据的接受
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/

void modbus_recv_rst(MODBUS_DEF *pt)
{
	pt->nTypeCounter=0;
	pt->nRecvLenth=0;
	pt->nRecvCounter=0;
	pt->dWaitTime=dTCounter;
	
}

int get_cmd_len(u8 cmd)
{
	int i;
	for(i=0;i<modbus_cmd_num;i++)
	{
		if(tModbusCmd[i].cmd==cmd)
		{
			return tModbusCmd[i].len;
		}
	}
	return -1;
}

/**************************************************************************
函数名称：Modbus_Recv
函数版本：1.00 
作者：   
创建日期：2008.11.15     
函数功能说明：Modbus规约的数据接收处理，此处有3.5位的时间判断处理 
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/

void  modbus_Recv(MODBUS_DEF *pt,unsigned char byRevData)
{
	int len;
	if(pt->bData)return ;
	if(dTCounter-pt->dWaitTime>T_5ms)		//检测到空闲间隔 3.5个字符
	{
		pt->recvbuf[pt->nRecvCounter++]=byRevData;
		switch(pt->nTypeCounter)
		{
			case 0:          //  子站地址
				if(byRevData==pt->slaveaddr)
				{
					pt->nTypeCounter++;
				}
				else
				{
					modbus_recv_rst(pt);
				}	
				break;
			case 1:		//功能码	
				pt->nTypeCounter++;
				break;			
			case 2:		//字节数
				len=get_cmd_len(pt->recvbuf[1]);
				pt->nTypeCounter++;		
				pt->nRecvCnt=0;
				if(len==0)
				{
					pt->nRecvLenth=byRevData+2;
				}
				else if(len>0)
				{
					pt->nRecvLenth=len+1;
				}
				else
				{
					modbus_recv_rst(pt);
				}
				
				break;
			case 3:        // CRC L 或其他数据
				pt->nRecvCnt++;

				if(pt->nRecvCnt>=pt->nRecvLenth)
				{
					modbus_recv_rst(pt);
					pt->bData=true;
				}
				break;
			default:   
				modbus_recv_rst(pt);
				break;
		}
	}
	else	//奇偶校验出错，舍弃已接收的数据
	{
		modbus_recv_rst(pt);	
	}
}

/**************************************************************************
函数名称：Modbus_ErrorEcho
函数版本：1.00 
作者：   
创建日期：2008.11.15     
函数功能说明：Modbus规约错误帧应答
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/

void modbus_errorecho(MODBUS_DEF *pt,unsigned char *ps,unsigned char err)
{

	BYTE *pd=pt->sendbuf;
	WORD crc;
	pd[0]=5;
	pd[1]=pt->tcmd[pt->bCurrent].slaveaddr;  // 地址
	pd[2]=ps[1]|0x80;          // 命令码
	pd[3]=err;                  // 错误码
	crc=Modbus_CRC16(&pd[1],3);
	pd[4]=(BYTE)(crc>>8);
	pd[5]=(BYTE)(crc);
}

/**************************************************************************
函数名称：Modbus_ReadData
函数版本：1.00 
作者：   
创建日期：2008.11.15     
函数功能说明：Modbus规约读数据应答，响应 02 03命令
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/

void modbus_send(MODBUS_DEF *pt)
{
	if(g_print_lnk && (g_print_port & (1<<pt->chnl)))
	{
		print_msg("TX_MODBUS:",&g_tRsComm[pt->chnl].sendbuf[1],g_tRsComm[pt->chnl].sendbuf[0]);
	}
	
	RS_Send_Enable(pt->chnl);
	g_tRsComm[pt->chnl].nSendCnt=1;   // 发送缓冲区的第一个字节为发送长度
	g_tRsComm[pt->chnl].bSend=true;
	pt->slaveaddr=g_tRsComm[pt->chnl].sendbuf[1];
	if(!g_bCommLed)g_bCommLed=true;
	
	//统计发送帧数
}

void modbus_read(MODBUS_DEF *pt,BYTE index)
{
 	BYTE *pd=pt->sendbuf;
 	int num=0;
	WORD crc;
	pt->readdi=pt->tcmd[index].di;

	pd[num++]=0;
	pd[num++]=pt->tcmd[index].slaveaddr;  // 地址
	pd[num++]=pt->tcmd[index].cmd;          // 命令码

	if(pt->cmd_dinum>1)	pd[num++]=(BYTE)(pt->tcmd[index].di>>8);                 
	pd[num++]=(BYTE)(pt->tcmd[index].di);       
	if(pt->cmd_datnum>1)	 pd[num++]=(BYTE)(pt->tcmd[index].num>>8);                 
	pd[num++]=(BYTE)(pt->tcmd[index].num);     	
	crc=Modbus_CRC16(&pd[1],num-1);
	pd[num++]=(BYTE)(crc>>8);
	pd[num++]=(BYTE)(crc);
	pd[0]=num-1;
	modbus_send(pt);
}

void modbus_write(MODBUS_DEF *pt,BYTE addr,WORD di,BYTE num,BYTE *pdat)
{
 	BYTE *pd=pt->sendbuf;
	WORD crc;
	int i,j;
	BYTE slaveaddr=addr;
	int cnt=0;
	for(j=0;j<pt->infnum;j++)
	{
		if((pt->tinf[j].type==MODBUS_INF_SENDADDR)&&(pt->tinf[j].slaveaddr==addr))
		{
			slaveaddr=pt->tinf[j].val;
		}
	}	
	pt->readdi=di;
	pd[cnt++]=0;
	pd[cnt++]=slaveaddr;  // 地址
	pd[cnt++]=pt->ykcmd;          // 命令码

	if(pt->cmd_dinum>1)	pd[cnt++]=(BYTE)(di>>8);                 
	pd[cnt++]=(BYTE)(di);                 
	for(i=0;i<num;i++)
	{
		pd[cnt++]=*pdat++;
	}
	crc=Modbus_CRC16(&pd[1],cnt-1);
	pd[cnt++]=(BYTE)(crc>>8);
	pd[cnt++]=(BYTE)(crc);
	pd[0]=cnt-1;
	modbus_send(pt);
}


void modbus_slave_yk(u8 ch,u8 ti,u8 cot,u8 v,u16 cp ,u8 yktype)
{
	LINK_TABLE * lt;
	struct do_table *dt;
	LINKYK_DEF *yk;
	char buf[128];	
		
	// 查找点表，如果找到，保存。
	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;
		}	

		if((cot&0x3f)==IEC_COT_ACT)
		{
			cot=IEC_COT_ACTCON|(cot&0xc0);
		}
		else if((cot&0x3f)==IEC_COT_DEACT)
		{
			cot=IEC_COT_DEACTCON|(cot&0xc0);
		}	
		
		yk->data[yktype].ti=ti;
		yk->data[yktype].cot=cot;
		yk->data[yktype].v=v;				
		yk->flag[yktype] = true;
		
		sprintf(buf,"级联遥控上行:(ch=%d,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);
	}
				
}



/**************************************************************************
函数名称：Modbus_Applay
函数版本：1.00 
作者：   
创建日期：2008.11.15     
函数功能说明：Modbus规约应用数据处理
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/
void modbus_Applay(MODBUS_DEF *pt)
{
	BYTE *pd;
	WORD crc,crc1;
	BYTE cmd;
	int len;
	if(!pt->bData)return;
	
	cmd=pt->recvbuf[1];
	len=get_cmd_len(cmd);

	if(len==0) //带字节数的报文 如 1 2 3 4
	{
		len=pt->recvbuf[2]+1; // 含字节数本身
		pd=&pt->recvbuf[3]; // 数据
	}
	else if(len>0) // 不带字节数的报文，如 5 0x0f 0x10等
	{
		pd=&pt->recvbuf[2]; // 数据
	}
	else
	{
		pt->bData=false;
		return;
	}

	if(g_print_lnk && (g_print_port & (1<<pt->chnl)))
	{
		print_msg("RX_MODBUS:",pt->recvbuf,(len+4));
	}
	crc=(WORD)(pt->recvbuf[len+2]<<8)+pt->recvbuf[len+3];	
	crc1=Modbus_CRC16(&pt->recvbuf[0],len+2);
	if(crc==crc1)	//crc校验通过,若不通过，不应答
	{
		MODBUS_CMD_DEF *pcmd;
		pcmd=&pt->tcmd[pt->bCurrent];
		if(cmd==pcmd->cmd)
		{
			int i;
			u16 ch,cp;
			LINK_TABLE * lt;
			ch=((pt->chnl+2)<<5)+pcmd->slaveaddr;	
			switch(pcmd->type) // 判断命令码
			{
				case MODBUS_TYPE_YX:					//
				{
					WORD dat;
					//struct di_table *dt;
					if(pcmd->readbit==1) // 按位取遥信
					{
						int bytenum=1;
						if(pcmd->bitbytes==2)
						{
							bytenum=2;
						}
						for(i=0;i<len/bytenum;i++)
						{
							int j,k=8;
							if(bytenum==2) // 按字读
							{
								if(!pt->dat_dir)
								{
									dat=(pd[0]<<8) | (pd[1]<<0);
								}
								else
								{
									dat=(pd[1]<<8) | (pd[0]<<0);
								}
								pd+=2;
								k=16;
							}
							else
							{
								dat=*pd++;
							}
							
							for(j=0;j<k;j++) //刷新遥信
							{
								
								//cp=(((pcmd->di+i)<<4)|j); // 将bit 位加入点号中
				
							#ifdef LINK_MODBUS_YX_CP
								cp=(pcmd->di+(k*i))+j;
							#else
								cp=((pcmd->di<<4)+(k*i))+j; // 将bit 位加入点号中
							#endif
								
								lt = tbl_link_di(ch,cp);
								
								if(lt)
								{
									int cpv,v;
									//dt = &g_di_table[lt->tbl_index];
									cpv=sw_di_get(lt->owner,lt->indexno);		
									v=((dat>>j)&0x01)+1;
									sw_di_set(lt->owner,lt->indexno,v); //转为双点保存
									if(cpv>=0&&pcmd->byxfirst) // 遥信已初始化过，产生soe
									{
										//rt_printf("%s:i=%d,j=%d,cp=%04x,lt->cp=%04x,cpv=%d,v=%d,dat=%x\r\n",__func__,i,j,cp,lt->cp,cpv,v,dat);
										if(v!=cpv)
										{
											struct timespec ts;
											clk_time_get(&ts);
											v = lt->is_inverse ? ((~v)&0x03) : v;
											soe_record_lnk(lt->cp ,v,&ts,(s32)lt,lt->is_mix,lt->cp_s);
										}
									}
								}									
							}
						}
					}
					else // 按字节取遥信
					{
						for(i=0;i<len;i++)
						{
							dat=*pd++;
							cp=pcmd->di+i; // 将bit 位加入点号中
							lt = tbl_link_di(ch,cp);
							if(lt)
							{
								int cpv,v;
								//dt = &g_di_table[lt->tbl_index];
								cpv=sw_di_get(lt->owner,lt->indexno);		
								v=dat+1;
								sw_di_set(lt->owner,lt->indexno,v);
								if(cpv>=0&&pcmd->byxfirst) // 遥信已初始化过，产生soe
								{
									if(v!=cpv)
									{
										struct timespec ts;
										clk_time_get(&ts);
										v = lt->is_inverse ? ((~v)&0x03) : v;
										soe_record_lnk(lt->cp ,v,&ts,(s32)lt,lt->is_mix,lt->cp_s);
									}
								}								
							}
							
						}

					}
					pcmd->byxfirst=true;
				}
				break;
				case MODBUS_TYPE_YC:					//
				case MODBUS_TYPE_DD:					//
				{
					BYTE num;
					struct ac_table *at;
					struct dd_table *dt;
					qs16 v;			
					float fv;
					if(pcmd->bitbytes==13||pcmd->bitbytes==4) //浮点
					{
						num=len/4;
					}
					else  // 整形 2字节
					{
						num=len/2;
					}		
					for(i=0;i<num;i++)
					{
						if(pcmd->bitbytes==13)  
						{
							union{
								float ff;
								u8 tt[4];
							}ff;	
						
							// 浮点
							if(!pt->dat_dir)
							{
							#ifdef MODE_LITTLE_ENDIAN
								ff.tt[3]=*pd++;
								ff.tt[2]=*pd++;
								ff.tt[1]=*pd++;
								ff.tt[0]=*pd++;
							#else	
								ff.tt[0]=*pd++;
								ff.tt[1]=*pd++;
								ff.tt[2]=*pd++;
								ff.tt[3]=*pd++;
							#endif
							}
							else
							{
								pd += CopySwap(ff.tt,pd,4,false);
							}
							fv = ff.ff;
							v=fv;
						}
						else if(pcmd->bitbytes==4)  
						{
							if(!pt->dat_dir)
							{
								v =  (pd[0]<<24) | (pd[1]<<16) |(pd[2]<<8) | (pd[3]<<0); // 高字节在前
							}
							else
							{
								v =  (pd[3]<<24) | (pd[2]<<16) |(pd[1]<<8) | (pd[0]<<0); // 高字节在前
							}
							pd += 4;
							fv=v;
						}
						else 
						{
							if(!pt->dat_dir)
							{
								v =  (pd[0]<<8) | (pd[1]<<0);
							}
							else
							{
								v =  (pd[1]<<8) | (pd[0]<<0);
							}
							pd += 2;
							fv=v;
						}

						cp=pcmd->di+i; 
						
						if(pcmd->type==MODBUS_TYPE_YC)
						{
							int divbase=pt->yc_rate;
							if(divbase==0)divbase=1;
							v*=(Q16_BASE/divbase);
							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;
								}
							}
						}
						else
						{
							lt = tbl_link_dd(ch,cp);
							if(lt)
							{
								dt = &g_dd_table[lt->tbl_index];
								if(dt->owner >0)
								{
									g_sw[dt->owner-1].dd[dt->indexno-1].fv= fv;
									g_sw[dt->owner-1].dd[dt->indexno-1].bchanged= 0;

								}
							}
						}
					}
				}
				
				break;	
				default:break;
				
			}
		}
		else if(cmd==pt->ykcmd) // 遥控应答
		{
			LINKYK_DEF *yk;
			yk = &g_lnk_yk[pt->yksendindex];			
			modbus_slave_yk(yk->chnl,yk->data[IECLINK_YK_SND].ti,7,yk->data[IECLINK_YK_SND].v,yk->cp_s,IECLINK_YK_ACK);
			modbus_slave_yk(yk->chnl,yk->data[IECLINK_YK_SND].ti,10,yk->data[IECLINK_YK_SND].v,yk->cp_s,IECLINK_YK_END);
		}
		pt->bRecvOk=true;
		pt->dsendtime=dTCounter;
	}
	else
	{
		rt_printf("\r\n modbus 接收报文crc校验错误 !\r\n");
	}
	pt->bData=false;
	modbus_recv_rst(pt);
}


/**************************************************************************
函数名称：Modbus_AutoTime
函数版本：1.00 
作者：   
创建日期：2008.11.15     
函数功能说明：Modbus规约定时处理函数，主要是超时处理
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/

void modbus_AutoTimer(MODBUS_DEF *pt)
{
	if((dTCounter-pt->dsendtime>pt->retrytime)||(pt->bRecvOk&&(dTCounter-pt->dsendtime>pt->sendinteraltime)))//  超时处理或接收到报文后延时sendinteraltime
	{
		pt->dsendtime=dTCounter;
		pt->bRecvOk=false;
		// 遥控
		 if(pt->yk_send_flag)
		{
			int i;			
			for(i=0;i<SWITCH_NUM_EXT_PUB;i++)
			{
				if(pt->yk_send_flag & (1<<i))
				{
					u16 val;
					u8 v,cot,ti,dat[8];
					LINKYK_DEF *yk = &g_lnk_yk[i];
					v=yk->data[IECLINK_YK_SND].v;
					cot=yk->data[IECLINK_YK_SND].cot;
					ti=yk->data[IECLINK_YK_SND].ti;

					if(v&0x80) // 遥控选择，遥控撤销，直接回复应答
					{
						if(pt->tyk.yk_st!= YK_STATUS_NONE && pt->tyk.yk_st!= YK_STATUS_TIMEOUT)
						{
							//已经有遥控命令选择或在执行
							cot|=IEC_COT_PN;
							memset(&pt->tyk,0,sizeof(REMOTEYKSTATUS));
						}
						else
						{
							// 记录选择动作
							pt->tyk.yk_st=YK_STATUS_SEL;
							pt->tyk.no=ti;
							pt->tyk.val=(v&0x3f);
							pt->tyk.wMaster=yk->cp_s;
							pt->tyk.dTStart=dTCounter;					
						}
						modbus_slave_yk(yk->chnl,ti,cot,v,yk->cp_s,IECLINK_YK_ACK);
						pt->bRecvOk=true;

						
					}					
					else if(cot==IEC_COT_DEACT) // 遥控选择，遥控撤销，直接回复应答
					{
						if(pt->tyk.yk_st!= YK_STATUS_SEL)
						{
							cot|=IEC_COT_PN;
						}					
						modbus_slave_yk(yk->chnl,ti,cot,v,yk->cp_s,IECLINK_YK_ACK);
						pt->bRecvOk=true;
						memset(&pt->tyk,0,sizeof(REMOTEYKSTATUS));
					}
					else // 遥控执行
					{

						if((ti != 0xff) 
							&& ((pt->tyk.yk_st!= YK_STATUS_SEL)  // 和遥控选择的数据不对应
							||(v !=pt->tyk.val)
							||(yk->cp_s !=pt->tyk.wMaster)
							||(ti != pt->tyk.no)))
						
						{
							cot|=IEC_COT_PN;
							modbus_slave_yk(yk->chnl,ti,cot,v,yk->cp_s,IECLINK_YK_ACK);
							pt->bRecvOk=true;
						}
						else
						{
							u8 num=0;
							pt->tyk.yk_st=YK_STATUS_EXE;
							pt->tyk.dTStart=dTCounter;					
							if(ti==45)v+=1; // 单点转为双点 2=合 1=分
							if(v==2) //遥控合
							{
								val=pt->ykval_h;
							}
							else
							{
								val=pt->ykval_f;

							}
							if(pt->ykcmd==0x0f||pt->ykcmd==0x10) // 0F和10命令，需增加线圈地址
							{
								dat[0]=(u8)(pt->coiladdr>>8);
								dat[1]=(u8)(pt->coiladdr);
								dat[2]=pt->ykbitbytes;  //个数		
								dat[3]=(u8)(val>>8);
								dat[4]=(u8)(val>>0);	
								num=pt->ykbitbytes+3;
							}	
							else
							{
								dat[0]=(u8)(val>>8);
								dat[1]=(u8)(val>>0);	
								num=pt->ykbitbytes;
							}
						#ifdef LINK_MODBUS_YK_MERGE
							if(v==2) //遥控合
							{
								modbus_write(pt,(yk->chnl&0x1f),yk->cp_s+1,num,dat);
							}
							else
							{
								modbus_write(pt,(yk->chnl&0x1f),yk->cp_s,num,dat);
							}
						#else
							modbus_write(pt,(yk->chnl&0x1f),yk->cp_s,num,dat);
						#endif
							
							pt->yksendindex=i;  //保存发送 g_lnk_yk 索引
						}
						memset(&pt->tyk,0,sizeof(REMOTEYKSTATUS));
					}	
					// 清除标志 
					g_lnk_yk[i].flag[IECLINK_YK_SND]=false;				
					pt->yk_send_flag &= ~(1<<i);

				}
			}
		}
		else if(pt->cmdnum>0)
		{
			pt->bCurrent++;	
			if(pt->bCurrent>=pt->cmdnum)pt->bCurrent=0;
			modbus_read(pt,pt->bCurrent);	
		}
	}

	if(pt->tyk.yk_st==YK_STATUS_SEL)
	{
		if(dTCounter- pt->tyk.dTStart>=tRunPara.dYKTime)//遥控选择超时
		{
			memset(&pt->tyk,0,sizeof(REMOTEYKSTATUS));
			// 置遥控超时状态，方便用户查看
			pt->tyk.yk_st = YK_STATUS_TIMEOUT; 
		}
	}
	
}

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





