
#include "modbus_tcp.h"
#include "trigger.h"

#if (MAX_MODBUS_TCP_NODE > 0)
#include "ethernet.h"

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

// 控制数据结构
typedef struct
{
	SocketCtrl * pSocket;

	// 控制控制
	int transing;			// 0, 空闲; 1, 发送请求，等待回包
	u16 transId;			// 发送的事务控制（从零开始自增）
	u32 begtime;			// 发送的时刻
	int expectAnswerPduLen;	// 期望的PDU长度

	// 发送命令的记录
	ModbusTcpADU request;	// 请求命令
	ModbusTcpADU answer;	// 应答命令

}ModbusTcpCtrl;

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

#define	MODBUSTCP_SIDX	TCP_CLIENT_SN_BEG

ModbusTcpCtrl g_modbusTcpCtrl[MAX_MODBUS_TCP_NODE];

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

// 发送数据
#define ModbusTcpSendData		EthernetSendData
// 接收数据
#define ModbusTcpGetData		EthernetGetData
// 已接收数据长度
#define ModbusTcpGetRsLen		EthernetGetRsLen
// 得到发送缓冲区空闲长度
#define ModbusTcpGetSdFreeLen	EthernetGetSdFreeLen

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

void InitModbusTcp()
{
	int i;
	memset(&g_modbusTcpCtrl, 0, sizeof(ModbusTcpCtrl)*MAX_MODBUS_TCP_NODE);

	for (i = 0; i < MAX_MODBUS_TCP_NODE; i++)
	{
		g_modbusTcpCtrl[i].pSocket = GetCtrlFromSocketIdx(MODBUSTCP_SIDX+i);
	}
}

// 异步功能，发送或接收modbustcp数据，完成通讯
void ModbusTcpServerRun(void)
{
	int i;
	int rslt;
	ModbusTcpADU * pRequestAdu;
	ModbusTcpADU * pAnswerAdu;

	for (i = 0; i < MAX_MODBUS_TCP_NODE; i++)
	{
		if (g_modbusTcpCtrl[i].transing == 1)	// 正在发送，等待回包
		{
			pRequestAdu = &(g_modbusTcpCtrl[i].request);
			pAnswerAdu 	= &(g_modbusTcpCtrl[i].answer);

			rslt = ModbusTcpGetRsLen(g_modbusTcpCtrl[i].pSocket);
			if (rslt >= g_modbusTcpCtrl[i].expectAnswerPduLen)
			{
				rslt = ModbusTcpGetData(g_modbusTcpCtrl[i].pSocket, pAnswerAdu->datbuff, g_modbusTcpCtrl[i].expectAnswerPduLen);
				if (rslt == g_modbusTcpCtrl[i].expectAnswerPduLen)
				{
					if (	pRequestAdu->normal.transId == pAnswerAdu->normal.transId &&
							pRequestAdu->normal.cmd == pAnswerAdu->normal.cmd &&
							// 其他检验
							1	)
					{
						// 收到正确回复
						printf("get ModbusTcp %d ACK\r\n", i);
					}
				}
				g_modbusTcpCtrl[i].transing = 0;
			}
			else if (rslt == LEN_ERR_ANSWER)		// 接收数据
			{
				rslt = ModbusTcpGetData(g_modbusTcpCtrl[i].pSocket, pAnswerAdu->datbuff, LEN_ERR_ANSWER);
				if (rslt == LEN_ERR_ANSWER)
				{
					if (	pRequestAdu->normal.transId == pAnswerAdu->normal.transId &&
							pRequestAdu->normal.cmd == (pAnswerAdu->normal.cmd | 0x80) &&
							// 其他检验
							1	)
					{
						// 收到错误回复
						printf("get ModbusTcp %d NAK\r\n", i);
					}
				}
				g_modbusTcpCtrl[i].transing = 0;
			}
			else if (rslt > 0)
			{
				printf("get ModbusTcp %d dat err len = %d\r\n", i, rslt);	// 长度不对
				g_modbusTcpCtrl[i].transing = 0;
			}
			else
			{
				u32 time;
				time = GetMsSoftTimer();
				if (time - g_modbusTcpCtrl[i].begtime > 100)
				{
					printf("wait ModbusTcp %d answer timout\r\n", i);	// 超时
					g_modbusTcpCtrl[i].transing = 0;
				}
				// 等待中
			}
		}
	}
}

u16 SwapHighLow(u16 data)
{
	u16 temp;
	temp = LOBYTE(data);		// DATA_L
	temp <<= 8;
	temp += HIBYTE(data);		// DATA_H;
	return temp;
}

// 功能: 写入多个寄存器
int ModbusTcpWriteRegs(int nidx, u16 addr, u16 * regAry, u16 nums)
{
	int i, pdulen;
	ModbusTcpADU * pRequestAdu;
//	ModbusTcpADU * pAnswerAdu;

	if (nidx < 0 || nidx > MAX_MODBUS_TCP_NODE || nums < 1 || regAry == NULL)
	{
		printf("ModbusTcpWriteRegs trans para err, nidx=%d, nums=%d\r\n", nidx, nums);
		return -1;
	}

	if (g_modbusTcpCtrl[nidx].transing != 0)
	{
		printf("ModbusTcpWriteRegs trans at %d is busy\r\n", nidx);
		return -1;
	}

	if (nums > MAX_WR_REG_NUMS)
	{
		nums = MAX_WR_REG_NUMS;
	}
	pdulen = 6 + nums*2;

	pRequestAdu = &(g_modbusTcpCtrl[nidx].request);
//	pAnswerAdu 	= &(g_modbusTcpCtrl[nidx].answer);

	//--------
	// MBAP
	pRequestAdu->writeRegArrayRequest.transId = SwapHighLow(g_modbusTcpCtrl[nidx].transId);	// 事务元标识符。从0开始自增
	pRequestAdu->writeRegArrayRequest.protId = SwapHighLow(0);	// 协议标识符。MODBUS 协议标识符为0x00，0x00
	pRequestAdu->writeRegArrayRequest.len = SwapHighLow(pdulen + 1);		// 帧长度。
	pRequestAdu->writeRegArrayRequest.unitId = 0x01;	// 单元标识符。

	//--------
	// MODBUS PDU
	pRequestAdu->writeRegArrayRequest.cmd = WRITE_MULTIPLE_REGISTER;	// 写多个寄存器
	pRequestAdu->writeRegArrayRequest.regBegAddr = SwapHighLow(addr);	// 寄存器起始位地址 0x0000至0xFFFF
	pRequestAdu->writeRegArrayRequest.regsNum = SwapHighLow(nums);		// 寄存器的数量 0x0001至0x007B（123）
	pRequestAdu->writeRegArrayRequest.bytes = nums * 2;	// 字节数  N = 寄存器数量 * 2
	for (i = 0; i < nums; i++)
	{
		pRequestAdu->writeRegArrayRequest.regsArray[i] = SwapHighLow(regAry[i]);	// 寄存器的值，MSB
	}

	//--------
	// 记录当前发送命令
	g_modbusTcpCtrl[nidx].transing = 1;		// 开始发送
	g_modbusTcpCtrl[nidx].begtime = GetMsSoftTimer();		// 记录开始发送的时间点
	g_modbusTcpCtrl[nidx].expectAnswerPduLen = 5;

	g_modbusTcpCtrl[nidx].transId++;
	//--------
	// 发送数据
	ModbusTcpSendData(g_modbusTcpCtrl[nidx].pSocket, pRequestAdu->datbuff, LEN_MBAP+pdulen);

	return 0;
}

#endif


