
#include "modbus_s.h"

#ifdef MODBUS_S_PORT

#include "inout.h"
#include "delay.h"
#include "trigger.h"

//-----------------------------------------------------------------
// 控制结构
u16 * mdbsReg[MODBUS_REG_MAX - MODBUS_REG_MIN + 1] = {NULL};		//	Modbus 从设备地址空间

ModbusCtrl g_modBusSCtrl;
Rs485Ctrl g_rs485SCtrl;

int ModbusSTx(Rs485Cmd * pCmd);				// 功能:发送一条MODBUS协议的应答
int ModbusSRx(u8 rDat);						// 功能:接收一条MODBUS协议的命令

int AddModbusSCmd(Rs485Cmd * pCmd);			// 添加命令到队列中
int GetModbusSCmd(Rs485Cmd * pCmd);			// 从队列中读取命令
int GetModbusSCmdBufLen(void);				// 得到队列中命令个数

void ReadModbusSData(u16 addr, u16 * pBuf, u16 len);	// 读数据
void WriteModbusSData(u16 addr, u16 * pBuf, u16 len);	// 写数据

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

/*-----------------------------------------------------------------
功能:初始化 Modbus 从设备串口
baud :		波特率
dat:		数据长度
parity:		校验位
stop:		停止位
mode:		数据模式
*/
void InitModbusS(BAUD_TypeDef baud, char dat, char parity, char stop, char mode)
{
	memset(&g_modBusSCtrl, 0, sizeof(ModbusCtrl));

	if (mode == 'A'	|| mode == 'a')
	{
		g_modBusSCtrl.modBusMode = 1;
	}
	else
	{
		g_modBusSCtrl.modBusMode = 0;
	}

	// 延时
	switch(baud)
	{
		// 数据位 + 1个起始位 + 奇偶校验位(无校验则没有) + 停止位
		// 根据波特率来计算 通讯延时, 单位us = 10000000 / baud(按照一个字节10位计算, 8 N 1)
		case B4800:
		{
			g_modBusSCtrl.modBusWait = 2200;
			break;
		}
		case B9600:
		{
			g_modBusSCtrl.modBusWait = 1100;
			break;
		}
		case B14400:
		{
			g_modBusSCtrl.modBusWait = 750;
			break;
		}
		case B19200:
		{
			g_modBusSCtrl.modBusWait = 600;
			break;
		}
		case B38400:
		{
			g_modBusSCtrl.modBusWait = 300;
			break;
		}
		case B57600:
		{
			g_modBusSCtrl.modBusWait = 200;
			break;
		}
		case B115200:
		{
			g_modBusSCtrl.modBusWait = 100;
			break;
		}
		case B230400:
		{
			g_modBusSCtrl.modBusWait = 50;
			break;
		}
		case B460800:
		{
			g_modBusSCtrl.modBusWait = 25;
			break;
		}
		case B921600:
		{
			g_modBusSCtrl.modBusWait = 13;
			break;
		}
		default:
		{
			g_modBusSCtrl.modBusWait = 0;
		}
	}
	if ((dat == '8') && (parity != 'N') && (parity != 'n'))	// 7位数据过滤校验位
	{
		g_modBusSCtrl.filterChk = 1; // 过滤数据校验位标志  1, 过滤
	}
	else
	{
		g_modBusSCtrl.filterChk = 0;
	}


#ifndef USART1_485OutEn
#define	USART1_485OutEn		DefOutEn
#endif

#ifndef USART1_485OutDis
#define	USART1_485OutDis	DefOutDis
#endif

#ifndef USART2_485OutEn
#define	USART2_485OutEn		DefOutEn
#endif

#ifndef USART2_485OutDis
#define	USART2_485OutDis	DefOutDis
#endif

#ifndef USART3_485OutEn
#define	USART3_485OutEn		DefOutEn
#endif

#ifndef USART3_485OutDis
#define	USART3_485OutDis	DefOutDis
#endif

#ifndef USART4_485OutEn
#define	USART4_485OutEn		DefOutEn
#endif

#ifndef USART4_485OutDis
#define	USART4_485OutDis	DefOutDis
#endif

#ifndef USART5_485OutEn
#define	USART5_485OutEn		DefOutEn
#endif

#ifndef USART5_485OutDis
#define	USART5_485OutDis	DefOutDis
#endif

#ifndef USART6_485OutEn
#define	USART6_485OutEn		DefOutEn
#endif

#ifndef USART6_485OutDis
#define	USART6_485OutDis	DefOutDis
#endif

	// 初始化串口
#if (MODBUS_S_PORT == COMM_USART1)
	InitUsart1(baud, dat, parity, stop);		// 串口1
	RegisterModbusCommFunc(&g_modBusSCtrl, Usart1SendData, Usart1GetData, Usart1CleanRsBuf, IsUsart1SendOver, USART1_485OutEn, USART1_485OutDis);
#elif (MODBUS_S_PORT == COMM_USART2)
	InitUsart2(baud, dat, parity, stop);		// 串口2
	RegisterModbusCommFunc(&g_modBusSCtrl, Usart2SendData, Usart2GetData, Usart2CleanRsBuf, IsUsart2SendOver, USART2_485OutEn, USART2_485OutDis);
#elif (MODBUS_S_PORT == COMM_USART3)
	InitUsart3(baud, dat, parity, stop);		// 串口3
	RegisterModbusCommFunc(&g_modBusSCtrl, Usart3SendData, Usart3GetData, Usart3CleanRsBuf, IsUsart3SendOver, USART3_485OutEn, USART3_485OutDis);
#elif (MODBUS_S_PORT == COMM_USART4)
	InitUsart4(baud, dat, parity, stop);		// 串口4
	RegisterModbusCommFunc(&g_modBusSCtrl, Usart4SendData, Usart4GetData, Usart4CleanRsBuf, IsUsart4SendOver, USART4_485OutEn, USART4_485OutDis);
#elif (MODBUS_S_PORT == COMM_USART5)
	InitUsart5(baud, dat, parity, stop);		// 串口5
	RegisterModbusCommFunc(&g_modBusSCtrl, Usart5SendData, Usart5GetData, Usart5CleanRsBuf, IsUsart5SendOver, USART5_485OutEn, USART5_485OutDis);
#elif (MODBUS_S_PORT == COMM_USART6)
	InitUsart6(baud, dat, parity, stop);		// 串口6
	RegisterModbusCommFunc(&g_modBusSCtrl, Usart6SendData, Usart6GetData, Usart6CleanRsBuf, IsUsart6SendOver, USART6_485OutEn, USART6_485OutDis);
#else
	RegisterModbusCommFunc(&g_modBusSCtrl, DefSendData, DefGetData, DefCleanRsBuf, DefIsSendOver, DefOutEn, DefOutDis);
#endif

	g_modBusSCtrl.CommOutDis();		// 关闭发送
}

/*-----------------------------------------------------------------
功能:发送一条ASCII格式MODBUS协议的应答,回应03控制字命令
*/
int Modbus_TX03A(Rs485Cmd * pCmd)
{
	int i = 0;
	u8 pSDat[MDBSRXLEN_A];		// 待发送数据
	u8 Lrc_check = 0;			// 和校验
	u16 data[MODBUS_REG_MAX - MODBUS_REG_MIN + 1] = {0};
	u8 temp;				// 临时变量
	u8 temp_data;			// 临时变量
	  
	if (pCmd == NULL)
	{
		return -1;
	}

	pSDat[i++] = ':';			//':'

	temp_data = pCmd->index;
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//IDX_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//IDX_L
	Lrc_check += temp_data;

	temp_data = pCmd->cmd;
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//CMD_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//CMD_L
	Lrc_check += temp_data;

	//数据个数
	temp_data = pCmd->rlen  << 1;
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Bytes Count_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Bytes Count_L
	Lrc_check += temp_data;

	//数据字节
	ReadModbusSData(pCmd->addr, &data[0], pCmd->rlen);
	for (int j = 0; j < pCmd->rlen; j++)
	{
		temp_data = HIBYTE(data[j]);
		temp = HIHFBYTE(temp_data);
		pSDat[i++] = RtuToAscii(temp);
		temp = LOHFBYTE(temp_data);
		pSDat[i++] = RtuToAscii(temp);
		Lrc_check += temp_data;

		temp_data = LOBYTE(data[j]);
		temp = HIHFBYTE(temp_data);
		pSDat[i++] = RtuToAscii(temp);
		temp = LOHFBYTE(temp_data);
		pSDat[i++] = RtuToAscii(temp);
		Lrc_check += temp_data;
	}

	Lrc_check = ~Lrc_check + 1;
	pSDat[i++] = RtuToAscii(HIHFBYTE(Lrc_check));			//LRC_H
	pSDat[i++] = RtuToAscii(LOHFBYTE(Lrc_check));			//LRC_L
	pSDat[i++] = 0x0D;										//CR
	pSDat[i++] = 0x0A;										//LF

	g_modBusSCtrl.ModBusCommSend(pSDat, i);		// 将数据放入发送缓冲区

	return 0;
}


/*-----------------------------------------------------------------
功能:发送一条ASCII格式MODBUS协议的应答,回应06控制字命令
*/
int Modbus_TX06A(Rs485Cmd * pCmd)
{
	int i = 0;
	u8 pSDat[MDBSRXLEN_A];		//待发送数据
	u8 Lrc_check = 0;			//和校验
	u8 temp;					//临时变量
	u8 temp_data;				//临时变量

	if (pCmd == NULL)
	{
		return -1;
	}

	pSDat[i++] = ':';			//':'

	temp_data = pCmd->index;
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//IDX_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//IDX_L
	Lrc_check += temp_data;

	temp_data = pCmd->cmd;
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//CMD_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//CMD_L
	Lrc_check += temp_data;

	temp_data = HIBYTE(pCmd->addr);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_L
	Lrc_check += temp_data;

	temp_data = LOBYTE(pCmd->addr);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_L
	Lrc_check += temp_data;

	temp_data = HIBYTE(pCmd->wrdat[0]);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Data_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Data_L
	Lrc_check += temp_data;

	temp_data = LOBYTE(pCmd->wrdat[0]);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Data_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Data_L
	Lrc_check += temp_data;

	Lrc_check = ~Lrc_check + 1;
	pSDat[i++] = RtuToAscii(HIHFBYTE(Lrc_check));			//LRC_H
	pSDat[i++] = RtuToAscii(LOHFBYTE(Lrc_check));			//LRC_L
	pSDat[i++] = 0x0D;										//CR
	pSDat[i++] = 0x0A;										//LF

	g_modBusSCtrl.ModBusCommSend(pSDat, i);		// 将数据放入发送缓冲区

	return	0;
}

/*-----------------------------------------------------------------
功能:发送一条ASCII格式MODBUS协议的应答,回应10H控制字命令
*/
int Modbus_TX10A(Rs485Cmd * pCmd)
{
	int i = 0;
	u8 pSDat[MDBSRXLEN_A];		//待发送数据
	u8 Lrc_check = 0;		//和校验
	u8 temp;		//临时变量
	u8 temp_data;		//临时变量
	 	  
	if (pCmd == NULL)
	{
		return -1;
	}

	pSDat[i++] = ':';			//':'

	temp_data = pCmd->index;
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//IDX_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//IDX_L
	Lrc_check += temp_data;

	temp_data = pCmd->cmd;
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//CMD_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//CMD_L
	Lrc_check += temp_data;

	temp_data = HIBYTE(pCmd->addr);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_L
	Lrc_check += temp_data;

	temp_data = LOBYTE(pCmd->addr);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//Addr_L
	Lrc_check += temp_data;

	temp_data = HIBYTE(pCmd->wlen);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//len_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//len_L
	Lrc_check += temp_data;

	temp_data = LOBYTE(pCmd->wlen);
	temp = HIHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//len_H
	temp = LOHFBYTE(temp_data);
	pSDat[i++] = RtuToAscii(temp);		//len_L
	Lrc_check += temp_data;

	Lrc_check = ~Lrc_check + 1;
	pSDat[i++] = RtuToAscii(HIHFBYTE(Lrc_check));			//LRC_H
	pSDat[i++] = RtuToAscii(LOHFBYTE(Lrc_check));			//LRC_L
	pSDat[i++] = 0x0D;										//CR
	pSDat[i++] = 0x0A;										//LF

	g_modBusSCtrl.ModBusCommSend(pSDat, i);		// 将数据放入发送缓冲区

	return	0;
}

/*-----------------------------------------------------------------
功能:发送一条RTU格式MODBUS协议的应答,回应03控制字命令
*/
int Modbus_TX03R(Rs485Cmd * pCmd)
{
	int i = 0;
	u8 pSDat[MDBSRXLEN_R];		//待发送数据
	u16 checkcrc;		//crc校验
	u16 data[MODBUS_REG_MAX - MODBUS_REG_MIN + 1] = {0};

	if (pCmd == NULL)
	{
		return -1;
	}

	pSDat[i++] = pCmd->index;		// ADR
	pSDat[i++] = pCmd->cmd;				// CMD

	pSDat[i++] = pCmd->rlen << 1;		// 字节数

	ReadModbusSData(pCmd->addr, &data[0], pCmd->rlen);
	for (int j = 0; j < pCmd->rlen; j++)
	{
		pSDat[i++] = HIBYTE(data[j]);		// DATA_H
		pSDat[i++] = LOBYTE(data[j]);		// DATA_L
	}

	checkcrc = ModbusCrc16(&pSDat[0], i);

	pSDat[i++] = HIBYTE(checkcrc);	// CRC_H
	pSDat[i++] = LOBYTE(checkcrc);	// CRC_L

	g_modBusSCtrl.ModBusCommSend(pSDat, i);		// 将数据放入发送缓冲区

	return 0;
}

/*-----------------------------------------------------------------
功能:发送一条RTU格式MODBUS协议的应答,回应06控制字命令
*/
int Modbus_TX06R(Rs485Cmd * pCmd)
{
	int i = 0;
	u8 pSDat[MDBSRXLEN_R];		//待发送数据
	u16 checkcrc;			//crc校验

	if (pCmd == NULL)
	{
		return -1;
	}

	pSDat[i++] = pCmd->index;		// ADR
	pSDat[i++] = pCmd->cmd;				// CMD
	pSDat[i++] = HIBYTE(pCmd->addr);		// ADDR_H
	pSDat[i++] = LOBYTE(pCmd->addr);		// ADDR_L

	pSDat[i++] = HIBYTE(pCmd->wrdat[0]);		// DATA_H
	pSDat[i++] = LOBYTE(pCmd->wrdat[0]);		// DATA_L

	checkcrc = ModbusCrc16(&pSDat[0], i);

	pSDat[i++] = HIBYTE(checkcrc);	// CRC_H
	pSDat[i++] = LOBYTE(checkcrc);	// CRC_L

	g_modBusSCtrl.ModBusCommSend(pSDat, i);		// 将数据放入发送缓冲区

	return 0;
}

/*-----------------------------------------------------------------
功能:发送一条RTU格式MODBUS协议的应答,回应10H控制字命令
*/
int Modbus_TX10R(Rs485Cmd * pCmd)
{
	int i = 0;
	u8 pSDat[MDBSRXLEN_R];		//待发送数据
	u8 checkcrc;		//crc校验

	if (pCmd == NULL)
	{
		return -1;
	}

	pSDat[i++] = pCmd->index;		// ADR
	pSDat[i++] = pCmd->cmd;		// CMD
	pSDat[i++] = HIBYTE(pCmd->addr);		// ADDR_H
	pSDat[i++] = LOBYTE(pCmd->addr);		// ADDR_L

	// 数据个数,单位字
	pSDat[i++] = HIBYTE(pCmd->wlen);		// LEN_H
	pSDat[i++] = LOBYTE(pCmd->wlen);		// LEN_L

	checkcrc = ModbusCrc16(&pSDat[0], i);

	pSDat[i++] = HIBYTE(checkcrc);	// CRC_H
	pSDat[i++] = LOBYTE(checkcrc);	// CRC_L

	g_modBusSCtrl.ModBusCommSend(pSDat, i);		// 将数据放入发送缓冲区

	return 0;
}

//-----------------------------------------------------------------
// 功能:发送一条MODBUS协议的回包,将数据放入发送缓冲区内
// 参数: pCmd:
// 返回值:	0:发送正常
//			-1:参数错误

int ModbusSTx(Rs485Cmd * pCmd)
{
	int result = 0;
	u8 cmd;

	if (pCmd == NULL)
	{
		return -1;
	}

	cmd = pCmd->cmd;

	if ((cmd != MODBUS_RD) &&
		(cmd != MODBUS_WR) &&
		(cmd != MODBUS_WR_MULTI) &&
		1)
	{
		return -1;
	}

	if (pCmd->index != 0 &&
			((pCmd->index & 0x80) == 0 || cmd == MODBUS_RD) &&
			1)
	{
		if (g_modBusSCtrl.modBusMode != 0)
		{// ASCII码模式
			if (cmd == MODBUS_RD)
			{
				Modbus_TX03A(pCmd);
			}
			else if (cmd == MODBUS_WR)
			{
				Modbus_TX06A(pCmd);
			}
			else if (cmd == MODBUS_WR_MULTI)
			{
				Modbus_TX10A(pCmd);
			}
		}
		else
		{// RTU模式
			if (cmd == MODBUS_RD)
			{
				Modbus_TX03R(pCmd);
			}
			else if (cmd == MODBUS_WR)
			{
				Modbus_TX06R(pCmd);
			}
			else if (cmd == MODBUS_WR_MULTI)
			{
				Modbus_TX10R(pCmd);
			}
		}
	}

	return result;
}

//-----------------------------------------------------------------
// 功能:接收一条MODBUS协议的命令
// 参数:
//		rDat:		本次收到的串口数据

// 返回值:	0: 接收正常	(收到的命令存放在 Rs485Cmd cmdbuf[MAX_485CMD] 中)
   
int ModbusSRx(u8 rDat)
{
	int i;
	int rst = -1;
	u32 time;
	static u32 timeBuf = 0;					
	static u8 rxDat[MDBSRXLEN_MAX] = {0};		// 待接收数据缓冲区
	static u8 beg = 0;					// 接收到起始符
	static u16 idx = 0;					// 有效索引
	static u16 num = 0;					// 接收到字符数
	static u8 rxDat_H = 0;				// 接收前半字节数据
	
	u16 checkcrc = 0;					// crc校验(RTU)
	u8 checksum = 0;					// 和校验(ASCII)

	Rs485Cmd newCmd;

	memset(&newCmd, 0, sizeof(Rs485Cmd));

	if (g_modBusSCtrl.modBusMode != 0)
	{// ASCII码模式
		if (g_modBusSCtrl.filterChk != 0)	// 7位数据过滤校验位
		{
			rDat &= (0x7F); 
		}
		
		time = GetUsSoftTimer();
		
		if (((time - timeBuf) > (g_modBusSCtrl.modBusWait * g_rs485SCtrl.modrsvTimout)) ||		// 读取超时时间
				(idx > MDBSRXLEN_A) ||		// 超长复位
				0)
		{// 重新接收数据包
			beg = 0;
			idx = 0;
			num = 1;
		}
		else
		{
			num++;
		}

		timeBuf = time;
		
		if (((rDat == ':') || (rDat == 0x0D) || (rDat == 0x0A)) ||
			 ((rDat >= '0') && (rDat <= '9')) ||
			 ((rDat >= 'a') && (rDat <= 'f')) ||
			 ((rDat >= 'A') && (rDat <= 'F')) ||
			 0)
		{// 接收到正确的数据
			if (beg == 1)
			{
				idx++;
			}
		}
		else
		{// 从新接收数据包
			beg = 0;	
			idx = 0;
		}
		
		if (rDat == ':')
		{// 接收到起始符
			beg = 1;
			idx = 0;
		}
		else if (rDat != 0x0A)
		{// 接收到普通数据
			if ((idx & 0x01) == 0)
			{//接收到偶数个数据,进行数据转换
				rxDat[(idx >> 1)-1] = MAKEBYTE(AsciiToRtu(rDat),AsciiToRtu(rxDat_H));
			}
			else
			{//接收到奇数个数据,将数据存放到临时寄存器中
				rxDat_H = rDat;  
			}
		}
		else if	(rDat == 0x0A)		// \n
		{// 接收到终止符
			if (rxDat_H == 0x0D)	// \r
			{// 终止符正常
				if ((idx & 0x01) == 0)
				{//数据个数基本符合要求
					idx = (idx >> 1) - 2;		//确定有效数据数组大小(不含校验位)
			
					//校验数据是否正确
					checksum = 0;			
					for (i = 0; i < idx; i++)
					{
						checksum += rxDat[i]; 
					}
					checksum = ~checksum + 1;
					
					if(checksum == rxDat[idx]) 
					{//lrc校验正确
						u8 index = rxDat[0];		// 数据站号
						int cur = 0;
						
						index &= 0x7f;
						for (i = 0; i < g_rs485SCtrl.idxNum; i++)
						{// 遍历查找是否是发给自己的命令
							if ((index == 0) ||
								(index == g_rs485SCtrl.idxList[i]) ||
								0)
							{
								cur = 1;
								break;
							}
						}
						
						if(cur == 1)
						{//站号正确
							//判断命令
							newCmd.index = rxDat[0];					// 站号
							newCmd.cmd = rxDat[1];						// 命令码
							newCmd.addr = MAKEWORD(rxDat[3],rxDat[2]);	// 数据地址
							
							switch(newCmd.cmd)
							{
								case MODBUS_RD:			//	03H (读取保持寄存器)
								{
									newCmd.rlen = MAKEWORD(rxDat[5],rxDat[4]);		//数据长度
									AddModbusSCmd(&newCmd);		// 增加命令
									rst = 0;
									break;
								}
									
								case MODBUS_WR:			//	06H (写单个保持寄存器)
								{
									newCmd.wrdat[0] = MAKEWORD(rxDat[5],rxDat[4]);		//数据
									newCmd.wlen = 1;									//数据长度
									AddModbusSCmd(&newCmd);		// 增加命令
									rst = 0;
									break;
								}

								case MODBUS_WR_MULTI:	//	10H (写多个保持寄存器)
								{
									newCmd.wlen = MAKEWORD(rxDat[5],rxDat[4]);		//数据长度
									for (i = 0; i < (rxDat[6]/2); i++)
									{ 
										newCmd.wrdat[i] = MAKEWORD(rxDat[i*2+8],rxDat[i*2+7]);	//数据
									} 
									AddModbusSCmd(&newCmd);		// 增加命令
									rst = 0;
									break;
								}
									
								default: 
									break;
							}	//switch(newCmd.cmd)                          
						}		//if (cur == 1)
					}			//if (checksum == rxDat[idx])
				}				//if ((idx & 0x01) == 0)
			}					//if (rxDat_H == 0x0D) 
			idx = 0;
			beg = 0;	// 从新接收数据包
		}						//if (rDat == 0x0A)
	}
	else
	{// RTU模式
		time = GetUsSoftTimer();

		if (((time - timeBuf) > (g_modBusSCtrl.modBusWait * g_rs485SCtrl.modrsvTimout)) ||	// 读取超时时间
				(idx > (MDBSRXLEN_R)) ||		// 超长复位
				0)
		{// 重新接收数据包
			if (num > 1)
			{
				printf("data packet restart, old num=%d, rDat=0x%x\r\n", num, rDat);
			}
			idx = 0;
			num = 1;
		}
		else
		{
			num++;
		}

		timeBuf = time;

		int receive = 0;		// 接收完成标志

		if (num < 8)		// 接收未完成
		{
			rxDat[idx] = rDat;
			idx++;
		}
		else if (num >= 8)
		{
			u16 len;

			if (rxDat[1] == MODBUS_WR_MULTI)
			{
				len = 9 + rxDat[6];
			}
			else
			{
				len = 8;
			}

			if (num < len)	// 接收未完成
			{
				rxDat[idx] = rDat;
				idx++;
			}
			else	// 接收完成
			{
				rxDat[idx] = rDat;
				receive = 1;
			}
		}

		if (receive == 1)
		{
			/*
			printf("receive a RTU modbus packet:");
			for (int j = 0; j < num; j++)
			{
				printf("\t0x%x", rxDat[j]);
			}
			printf("\r\n");
			*/

			//校验数据是否正确
			checkcrc = ModbusCrc16(&rxDat[0], num-2);

			if (rxDat[num-2] == HIBYTE(checkcrc) && rxDat[num-1] == LOBYTE(checkcrc))
			{//crc校验正确
				u8 index = rxDat[0];		// 站号
				int cur = 0;

				index &= 0x7f;				// 只查找小于128的站号
				for (i = 0; i < g_rs485SCtrl.idxNum; i++)
				{// 遍历查找是否是发给自己的命令
					if ((index == 0) ||
							(index == g_rs485SCtrl.idxList[i]) ||
							0)
					{
						cur = 1;
						break;
					}
				}

				if(cur == 1)
				{//站号正确
					newCmd.index = rxDat[0];					// 站号
					newCmd.cmd = rxDat[1];						// 命令码
					newCmd.addr = MAKEWORD(rxDat[3],rxDat[2]);	// 数据地址

					switch(newCmd.cmd)
					{
						case MODBUS_RD:			//	03H (读取保持寄存器)
						{
							newCmd.rlen = MAKEWORD(rxDat[5],rxDat[4]);		//数据长度
							AddModbusSCmd(&newCmd);		// 增加命令
							rst = 0;
							break;
						}

						case MODBUS_WR:			//	06H (写单个保持寄存器)
						{
							newCmd.wrdat[0] = MAKEWORD(rxDat[5],rxDat[4]);		//数据
							newCmd.wlen = 1;									//数据长度
							AddModbusSCmd(&newCmd);		// 增加命令
							rst = 0;
							break;
						}

						case MODBUS_WR_MULTI:	//	10H (写多个保持寄存器)
						{
							newCmd.wlen = MAKEWORD(rxDat[5],rxDat[4]);		//数据长度
							for (i = 0; i < newCmd.wlen; i++)
							{
								newCmd.wrdat[i] = MAKEWORD(rxDat[8+i*2], rxDat[7+i*2]);		//数据
							}
							AddModbusSCmd(&newCmd);		// 增加命令
							rst = 0;
							break;
						}

						default:
							break;
					}
				}
				else
				{
					printf("index error, index=%d\r\n", index);
				}
			}
			else
			{
				printf("check crc error, calc crc:0x%x 0x%x, receive crc:0x%x 0x%x\r\n",
						HIBYTE(checkcrc), LOBYTE(checkcrc), rxDat[num-2], rxDat[num-1]);
			}
			idx = 0;
			num = 0;			// 重新接收数据包
		}
	}

	return rst;
}
 
//-----------------------------------------------------------------

// idx 从站号
void InitModbusSCtrl(u8 idx, int rsvtimout)
{
	memset(&g_rs485SCtrl, 0, sizeof(Rs485Ctrl));

	g_rs485SCtrl.init = 1;			// 初始化完成
	g_rs485SCtrl.idxList[g_rs485SCtrl.idxNum] = idx;	// 站号
	g_rs485SCtrl.idxNum++;
	
	// 读取超时时间
	if (rsvtimout < 10)
	{
		g_rs485SCtrl.modrsvTimout = 10;
	}
	else if (rsvtimout > 100)
	{
		g_rs485SCtrl.modrsvTimout = 100;
	}
	else
	{
		g_rs485SCtrl.modrsvTimout = rsvtimout;
	}
}

// 注册外部响应函数
void RegModbusSCmdProc(Resv485ExProc exProc)
{
	g_rs485SCtrl.resv485exproc = exProc;
}

// 增加附属从站号
void AddModbusSIdx(u8 idx)
{
	if (g_rs485SCtrl.idxNum < MODBUS_IDXMAX)
	{
		g_rs485SCtrl.idxList[g_rs485SCtrl.idxNum] = idx;	// 站号
		g_rs485SCtrl.idxNum++;
	}
}

// 将命令放入缓冲区内
int AddModbusSCmd(Rs485Cmd * pCmd)
{
	Rs485Ctrl * p485Ctrl = &g_rs485SCtrl;

	if (p485Ctrl != NULL && pCmd != NULL)
	{
		if (p485Ctrl->bufCmdNum < MAX_485CMD && p485Ctrl->bufTail < MAX_485CMD)
		{
			memcpy(&(p485Ctrl->cmdbuf[p485Ctrl->bufTail]), pCmd, sizeof(Rs485Cmd));
			p485Ctrl->bufTail++;
			if (p485Ctrl->bufTail >= MAX_485CMD)
			{
				p485Ctrl->bufTail = 0;
			}
			p485Ctrl->bufCmdNum++;
			return p485Ctrl->bufCmdNum;
		}
		return -2;
	}

	return -1;
}

// 得到一条缓冲区内的命令
int GetModbusSCmd(Rs485Cmd * pCmd)
{
	Rs485Ctrl * p485Ctrl = &g_rs485SCtrl;

	if (p485Ctrl != NULL && pCmd != NULL)
	{
		if (p485Ctrl->bufCmdNum > 0 && p485Ctrl->bufHead < MAX_485CMD)
		{
			memcpy(pCmd, &(p485Ctrl->cmdbuf[p485Ctrl->bufHead]), sizeof(Rs485Cmd));
			p485Ctrl->bufHead++;
			if (p485Ctrl->bufHead >= MAX_485CMD)
			{
				p485Ctrl->bufHead = 0;
			}
			p485Ctrl->bufCmdNum--;
			return p485Ctrl->bufCmdNum;
		}
		else
		{
			return -2;
		}
	}

	return -1;
}

int GetModbusSCmdBufLen(void)
{
	return g_rs485SCtrl.bufCmdNum;
}

// modbus从设备,异步响应函数
int ModbusSTask(void)
{
	static u32 lastTime;	// 单位us

	static Rs485Cmd cmd;

	Rs485Ctrl * p485Ctrl = &g_rs485SCtrl;

	if (p485Ctrl == NULL)
	{
		return -1;
	}

	if (p485Ctrl->init == 0)
	{// 没有初始化,直接跳出
		return -1;
	}

	switch(p485Ctrl->steps)
	{
		case 0:		// 待机状态
		{
			if (1)
			{// 接收串口缓冲区内数据
				u8 rDat;
				int len;
				int rslt;
				do
				{
					len = g_modBusSCtrl.ModBusCommReceive(&rDat, 1);	// 从缓冲区读取数据
					if (len == 1)
					{// 接收到串口数据
						rslt = ModbusSRx(rDat);
						if (rslt == 0)
						{// 接收到一个数据包
							break;
						}
					}
					else
					{
						break;
					}
				}while(1);
			}

			if (GetModbusSCmdBufLen() != 0)// 缓冲区有数据
			{
				memset(&cmd, 0, sizeof(Rs485Cmd));
				GetModbusSCmd(&cmd);			// 得到命令
				if (cmd.index != 0 &&
						((cmd.index & 0x80) == 0 || cmd.cmd == MODBUS_RD) &&
						1)
				{// 需要回包
					lastTime = GetUsSoftTimer();
					p485Ctrl->steps++;
				}
				else
				{// 不需要回包
					p485Ctrl->steps = 5;
				}
			}
			break;
		}

		case 1:		// 数据发送允许
		{
			if ((GetUsSoftTimer() - lastTime) > (g_modBusSCtrl.modBusWait * 2))
			{
				g_modBusSCtrl.CommOutEn();
				lastTime = GetUsSoftTimer();
				p485Ctrl->steps++;
			}
			break;
		}

		case 2:		// 填充回包数据
		{
			if (GetUsSoftTimer() - lastTime > 100)
			{
				ModbusSTx(&cmd);
				p485Ctrl->steps++;
			}
			break;
		}

		case 3:		// 等待发送完成
		{
			if (g_modBusSCtrl.IsModBusCommSendOver() == TRUE)
			{
				lastTime = GetUsSoftTimer();
				p485Ctrl->steps++;
			}
			break;
		}

		case 4:		// 等待最后一个字节发送完成
		{
			if ((GetUsSoftTimer() - lastTime) > (g_modBusSCtrl.modBusWait * 2))
			{
				p485Ctrl->steps++;
			}
			break;
		}

		case 5:		// 执行外部函数
		{
			g_modBusSCtrl.CommOutDis();	// 数据发送禁止
			if (cmd.cmd == MODBUS_WR || cmd.cmd == MODBUS_WR_MULTI)
			{
				WriteModbusSData(cmd.addr, &cmd.wrdat[0], cmd.wlen);
			}
			if (g_rs485SCtrl.resv485exproc != NULL)
			{
				g_rs485SCtrl.resv485exproc(&cmd);
			}
			else
			{
				printf("resv485exproc is NULL\r\n");
			}
			p485Ctrl->steps = 0;
			break;
		}

		default:
		{
			g_modBusSCtrl.CommOutDis();	// 数据发送禁止
			p485Ctrl->steps = 0;
			break;
		}
	}
	return p485Ctrl->steps;
}


//------------------------------------------------------------------------------------------
// 初始化寄存器组
int InitModbusReg(u16 addr, u16 * pBuf, u16 len)
{
	if (len != 0 && pBuf != NULL)
	{
		if ((addr + len - 1) > MODBUS_REG_MAX)
		{
			printf("[Warning]: modbus addr outsize !! addr=0x%x, max=0x%x\r\n", (addr + len - 1), MODBUS_REG_MAX);
		}
		else if (addr < MODBUS_REG_MIN)
		{
			printf("[Warning]: modbus addr outsize !! addr=0x%x, min=0x%x\r\n", addr, MODBUS_REG_MIN);
		}
		else
		{
			for (int i = addr; i < (addr+len); i++)
			{
				mdbsReg[i - MODBUS_REG_MIN] = pBuf++;
			}
			return len;
		}
	}
	return 0;
}

// 读数据
void ReadModbusSData(u16 addr, u16 * pBuf, u16 len)
{
	if (len != 0 && pBuf != NULL)
	{
		if ((addr + len - 1) > MODBUS_REG_MAX)
		{
			printf("[Warning]: modbus addr outsize !! addr=0x%x, max=0x%x\r\n", (addr + len - 1), MODBUS_REG_MAX);
		}
		else if (addr < MODBUS_REG_MIN)
		{
			printf("[Warning]: modbus addr outsize !! addr=0x%x, min=0x%x\r\n", addr, MODBUS_REG_MIN);
		}
		else
		{
			for (int i = addr; i < (addr+len); i++)
			{
				if (mdbsReg[i - MODBUS_REG_MIN] == NULL)
				{
					printf("[Warning]: modbus addr NULL !! addr=0x%x\r\n", i);
				}
				else
				{
					*pBuf++ = *mdbsReg[i - MODBUS_REG_MIN];
				}
			}
		}
	}
}

// 写数据
void WriteModbusSData(u16 addr, u16 * pBuf, u16 len)
{
	if (len != 0 && pBuf != NULL)
	{
		if ((addr + len - 1) > MODBUS_REG_MAX)
		{
			//printf("[Warning]: modbus addr outsize !! addr=0x%x, max=0x%x\r\n", (addr + len - 1), MODBUS_REG_MAX);
		}
		else if (addr < MODBUS_REG_MIN)
		{
			//printf("[Warning]: modbus addr outsize !! addr=0x%x, min=0x%x\r\n", addr, MODBUS_REG_MIN);
		}
		else
		{
			for (int i = addr; i < (addr+len); i++)
			{
				if (mdbsReg[i - MODBUS_REG_MIN] == NULL)
				{
					//printf("[Warning]: modbus addr NULL !! addr=0x%x\r\n", i);
				}
				else
				{
					*mdbsReg[i - MODBUS_REG_MIN] = *pBuf++;
				}
			}
		}
	}
}

#endif

