
#include "one2onecomm.h"
#include "delay.h"
#include "crc16.h"
#include "trigger.h"

//-----------------------------------------------------------------
// 控制数据结构
typedef struct
{
	u16 modBusWait;		// 通讯延时, 单位us

	// 通讯函数指针
	UsartSendData One2OneCommSend;			// 发送数据
	UsartGetData One2OneCommReceive;			// 接收数据
	IsUsartSendOver IsOne2OneCommSendOver;	// 判断发送缓冲区是否为空

}One2OneCommCtrl;

// 控制结构
One2OneCommCtrl g_one2onecommCtrl;

#define MAX_ONE2ONE_CMD			10			// 最大支持的命令个数

typedef struct
{
	One2OneCmd cmdbuf[MAX_ONE2ONE_CMD];

	u8 sending;		// =1,发送中

	u8 bufCmdNum;		// 命令个数 != 0, 有新命令
	u8 bufHead;
	u8 bufTail;

	u8 steps;

	ResvOne2OneExProc resvexproc;		// 收到数据处理函数

	u16 rsvTimout;		// 读取超时时间, 单位为 100us

}One2OneCtrl;

One2OneCtrl g_one2oneCtrl;

//-----------------------------------------------------------------
// 功能：初始化一对一通讯
void InitOne2OneComm(int usart, BAUD_TypeDef baud, char dat, char parity, char stop);
int One2OneCommTx(u16 addr, u16 * pData, u8 len, int steps);		// 功能:发送
int One2OneCommRx(u8 rDat);											// 功能:接收

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

// 注册通讯函数
void RegisterOne2OneCommFunc(One2OneCommCtrl* pCtrl, UsartSendData send, UsartGetData get, IsUsartSendOver sdover)
{
	pCtrl->One2OneCommSend = send;
	pCtrl->One2OneCommReceive = get;
	pCtrl->IsOne2OneCommSendOver = sdover;
}


/*-----------------------------------------------------------------
功能:初始化设备串口
usart;		串口通道
baud :		波特率
dat:		数据长度
parity:		校验位
stop:		停止位
*/
void InitOne2OneComm(int usart, BAUD_TypeDef baud, char dat, char parity, char stop)
{
	memset(&g_one2onecommCtrl, 0, sizeof(One2OneCommCtrl));

	// 延时
	switch(baud)
	{
		// 根据波特率来计算 通讯延时, 单位us = 10000000 / baud
		case B4800:
		{
			g_one2onecommCtrl.modBusWait = 2200;
			break;
		}
		case B9600:
		{
			g_one2onecommCtrl.modBusWait = 1100;
			break;
		}
		case B14400:
		{
			g_one2onecommCtrl.modBusWait = 750;
			break;
		}
		case B19200:
		{
			g_one2onecommCtrl.modBusWait = 600;
			break;
		}
		case B38400:
		{
			g_one2onecommCtrl.modBusWait = 300;
			break;
		}
		case B57600:
		{
			g_one2onecommCtrl.modBusWait = 200;
			break;
		}
		case B115200:
		{
			g_one2onecommCtrl.modBusWait = 100;
			break;
		}
		case B230400:
		{
			g_one2onecommCtrl.modBusWait = 50;
			break;
		}
		case B460800:
		{
			g_one2onecommCtrl.modBusWait = 25;
			break;
		}
		case B921600:
		{
			g_one2onecommCtrl.modBusWait = 13;
			break;
		}
		default:
		{
			break;
		}
	}

	// 初始化串口
	switch(usart)
	{
#ifdef COMM_USART1
		case COMM_USART1:
		{
			InitUsart1(baud, dat, parity, stop);		// 串口1
			RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart1SendData, Usart1GetData, IsUsart1SendOver);
			break;
		}
#endif
#ifdef COMM_USART2
		case COMM_USART2:
		{
			InitUsart2(baud, dat, parity, stop);		// 串口2
			RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart2SendData, Usart2GetData, IsUsart2SendOver);
			break;
		}
#endif
#ifdef COMM_USART3
		case COMM_USART3:
		{
			InitUsart3(baud, dat, parity, stop);		// 串口3
			RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart3SendData, Usart3GetData, IsUsart3SendOver);
			break;
		}
#endif
#ifdef COMM_USART4
		case COMM_USART4:
		{
			InitUsart4(baud, dat, parity, stop);		// 串口4
			RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart4SendData, Usart4GetData, IsUsart4SendOver);
			break;
		}
#endif
#ifdef COMM_USART5
		case COMM_USART5:
		{
			InitUsart5(baud, dat, parity, stop);		// 串口5
			RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart5SendData, Usart5GetData, IsUsart5SendOver);
			break;
		}
#endif
		default:
		{
			break;
		}
	}
}

//-----------------------------------------------------------------
// 功能:发送
// 参数:
//		addr:	数据起始地址: 0000H~FFFFH
//		data:	数据内容:	单位:字
//		len:	数据长度
//		steps:-1,同步执行
//			  1,发送数据
//			  2,等待数据发送完成
// 返回值:
//		>0:对应步骤执行完成
//		0:数据未发送完成
//		-1: 参数错误
//		-2: 发送超时
int One2OneCommTx(u16 addr, u16 * pData, u8 len, int steps)
{
	int i, timeout, result;
	u16 checkcrc;			// CRC 校验
	u16 data;
	u8 pSDat[5+2*MAX_REG_WR];			// 待发送数据

	i = 0;

	if (pData == NULL || len > MAX_REG_WR)
	{
		return -1;
	}

	if (steps == 1 || steps == -1)
	{
		i = 0;
		result = 0;

		pSDat[i++] = HIBYTE(addr);		// ADDR_H
		pSDat[i++] = LOBYTE(addr);		// ADDR_L

		pSDat[i++] = len;

		for (int j = 0; j < len; j++)
		{
			data = pData[j];

			pSDat[i++] = HIBYTE(data);		// DATA_H
			pSDat[i++] = LOBYTE(data);		// DATA_L
		}

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

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

		g_one2onecommCtrl.One2OneCommSend(pSDat, i);
	}

	if (steps == 2)
	{
		if (g_one2onecommCtrl.IsOne2OneCommSendOver() != TRUE)
		{
			return 0;
		}
	}
	else if (steps == -1)
	{
		timeout = (u8)(i*2) + 4;	// 超时时间(每个字节发送时长*2*字节数 + 每个字节发送时长*4 )

		do	//等待发送完成
		{
			if (g_one2onecommCtrl.IsOne2OneCommSendOver() == TRUE)
			{
				break;
			}

			if (timeout-- <= 0)
			{
				result = -2;
				break;
			}

			DelayUs(g_one2onecommCtrl.modBusWait);

		}while(1);
	}

	if (steps != -1)
	{
		return steps;
	}

	return result;
}

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

int One2OneCommRx(u8 rDat)
{
	int rst = -1;
	u32 time;
	static u32 timeBuf = 0;
	static u8 rxDat[15+2*MAX_REG_WR];		// 待接收数据缓冲区
	static u8 idx = 0;					// 有效索引
	static u8 num = 0;					// 接收到字符数

	u16 checkcrc = 0;					// crc校验

	One2OneCmd newCmd;

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

	time = Get100UsSoftTimer();	// 100us

	if (0 ||
			((time - timeBuf) > g_one2oneCtrl.rsvTimout) ||		// 读取超时时间, 单位为 100us
			(idx >= 15+2*MAX_REG_WR) ||		// 超长复位
			0)
	{// 重新接收数据包
		if (num > 1)
		{
			printf("data begin, num=%d\r\n", num);
		}
		idx = 0;
		num = 1;
	}
	else
	{
		num++;
	}

	timeBuf = time;

	if (num < 7)		// 接收未完成
	{
		rxDat[idx] = rDat;
		//printf("num=%d, rxDat[%d] is 0x%x \r\n", num, idx, rxDat[idx]);
		idx++;
	}
	else
	{
		rxDat[idx] = rDat;

		if (num == rxDat[2]*2 + 5)		// 接收完成
		{
			//校验数据是否正确
			checkcrc = CalcCrc16(&rxDat[0], num-2);

			if (rxDat[num-2] == HIBYTE(checkcrc) && rxDat[num-1] == LOBYTE(checkcrc))
			{//crc校验正确
				newCmd.addr = MAKEWORD(rxDat[1],rxDat[0]);	// 数据地址
				newCmd.rdlen = rxDat[2];
				for (int i = 0; i < newCmd.rdlen; i++)
				{
					newCmd.rddat[i] = MAKEWORD(rxDat[i*2+4],rxDat[i*2+3]);		//数据
				}
				// 执行外部函数
				if (g_one2oneCtrl.resvexproc != NULL)
				{
					g_one2oneCtrl.resvexproc(&newCmd);
				}
				rst = 0;
			}
			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;			// 重新接收数据包
		}
		else
		{
			idx++;
		}
	}

	return rst;
}

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

void InitOne2OneCtrl(int usart, BAUD_TypeDef baud, char dat, char parity, char stop, int rsvtimout)
{
	InitOne2OneComm(usart, baud, dat, parity, stop);

	memset(&g_one2oneCtrl, 0, sizeof(One2OneCtrl));

	g_one2oneCtrl.rsvTimout = rsvtimout;
}

void RegOne2OneCmdProc(ResvOne2OneExProc proc)
{
	g_one2oneCtrl.resvexproc = proc;
}

int AddOne2OneCmd(One2OneCmd * pCmd)
{
	if (pCmd != NULL)
	{
		if (g_one2oneCtrl.bufCmdNum < MAX_ONE2ONE_CMD && g_one2oneCtrl.bufHead < MAX_ONE2ONE_CMD)
		{
			memcpy(&(g_one2oneCtrl.cmdbuf[g_one2oneCtrl.bufHead]), pCmd, sizeof(One2OneCmd));
			g_one2oneCtrl.bufHead++;
			if (g_one2oneCtrl.bufHead >= MAX_ONE2ONE_CMD)
			{
				g_one2oneCtrl.bufHead = 0;
			}
			g_one2oneCtrl.bufCmdNum++;
			return g_one2oneCtrl.bufCmdNum;
		}
		printf("bufcmd full\r\n");
		return -2; 
	}

	printf("para error\r\n");
	return -1;
}

void One2OneTask(void)
{
	int rslt;

	// 异步发送数据
	if (g_one2oneCtrl.sending == 0 &&
			g_one2oneCtrl.bufCmdNum > 0 &&
			g_one2oneCtrl.steps == 0)
	{
		g_one2oneCtrl.sending = 1;
		g_one2oneCtrl.steps = 1;
	}

	if (g_one2oneCtrl.sending != 0)
	{
		One2OneCmd *pCmd;
		pCmd = &(g_one2oneCtrl.cmdbuf[g_one2oneCtrl.bufTail]);

		if (g_one2oneCtrl.steps > 0 && g_one2oneCtrl.steps < 3)
		{
			rslt = One2OneCommTx(pCmd->addr, &pCmd->wrdat[0], pCmd->wrlen, g_one2oneCtrl.steps);

			if (rslt == g_one2oneCtrl.steps)
			{
				g_one2oneCtrl.steps++;
			}
		}
		else if (g_one2oneCtrl.steps == 3)
		{
			if (g_one2oneCtrl.bufCmdNum > 0)
			{
				g_one2oneCtrl.bufCmdNum--;
			}
			g_one2oneCtrl.steps = 0;
			g_one2oneCtrl.sending = 0;
			g_one2oneCtrl.bufTail++;
			if (g_one2oneCtrl.bufTail >= MAX_ONE2ONE_CMD)
			{
				g_one2oneCtrl.bufTail = 0;
			}
		}
	}

	// 接收串口缓冲区内数据
	u8 rDat;
	int len;
	do
	{
		len = g_one2onecommCtrl.One2OneCommReceive(&rDat, 1);	// 从缓冲区读取数据
		if (len == 1)
		{// 接收到串口数据
			rslt = One2OneCommRx(rDat);
			if (rslt == 0)
			{// 接收到一个数据包
				break;
			}
		}
		else
		{
			break;
		}
	}while(1);
}

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




