
#include "ef_a.h"

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

#ifndef EF_NUM
#define EF_NUM			1
#endif

EFCommCtrl g_efCommCtrl[EF_NUM];

void EFDefOutEn(void)
{
}

void EFDefOutDis(void)
{
}

void RegisterEFCommFunc(EFCommCtrl* pCtrl, UsartSendData send, UsartGetData get, UsartCleanRsBuf clean, IsUsartSendOver sdover, CommOutFunc outen, CommOutFunc outdis)
{
	pCtrl->EFCommSend = send;
	pCtrl->EFCommReceive = get;
	pCtrl->EFCommCleanRsBuf = clean;
	pCtrl->IsEFCommSendOver = sdover;

	pCtrl->CommOutEn = outen;
	pCtrl->CommOutDis = outdis;
}

void InitEF(int idx, int usart, BAUD_TypeDef baud, char dat, char parity, char stop)
{
	if (idx < 0 || idx >= EF_NUM)
	{
		return;
	}

	memset(&g_efCommCtrl[idx], 0, sizeof(EFCommCtrl));

	// 延时
	switch(baud)
	{
		// 数据位 + 1个起始位 + 奇偶校验位(无校验则没有) + 停止位
		// 根据波特率来计算 通讯延时, 单位us = 10000000 / baud(按照一个字节10位计算, 8 N 1)
		case B4800:
		{
			g_efCommCtrl[idx].efSendWait = 2200;
			break;
		}
		case B9600:
		{
			g_efCommCtrl[idx].efSendWait = 1100;
			break;
		}
		case B14400:
		{
			g_efCommCtrl[idx].efSendWait = 750;
			break;
		}
		case B19200:
		{
			g_efCommCtrl[idx].efSendWait = 600;
			break;
		}
		case B38400:
		{
			g_efCommCtrl[idx].efSendWait = 300;
			break;
		}
		case B57600:
		{
			g_efCommCtrl[idx].efSendWait = 200;
			break;
		}
		case B115200:
		{
			g_efCommCtrl[idx].efSendWait = 100;
			break;
		}
		case B230400:
		{
			g_efCommCtrl[idx].efSendWait = 50;
			break;
		}
		case B460800:
		{
			g_efCommCtrl[idx].efSendWait = 25;
			break;
		}
		case B921600:
		{
			g_efCommCtrl[idx].efSendWait = 13;
			break;
		}
		default:
		{
			g_efCommCtrl[idx].efSendWait = 0;
		}
	}

#ifndef USART1_485OutEn
#define	USART1_485OutEn		EFDefOutEn
#endif

#ifndef USART1_485OutDis
#define	USART1_485OutDis	EFDefOutDis
#endif

#ifndef USART2_485OutEn
#define	USART2_485OutEn		EFDefOutEn
#endif

#ifndef USART2_485OutDis
#define	USART2_485OutDis	EFDefOutDis
#endif

#ifndef USART3_485OutEn
#define	USART3_485OutEn		EFDefOutEn
#endif

#ifndef USART3_485OutDis
#define	USART3_485OutDis	EFDefOutDis
#endif

#ifndef USART4_485OutEn
#define	USART4_485OutEn		EFDefOutEn
#endif

#ifndef USART4_485OutDis
#define	USART4_485OutDis	EFDefOutDis
#endif

#ifndef USART5_485OutEn
#define	USART5_485OutEn		EFDefOutEn
#endif

#ifndef USART5_485OutDis
#define	USART5_485OutDis	EFDefOutDis
#endif

#ifndef USART6_485OutEn
#define	USART6_485OutEn		EFDefOutEn
#endif

#ifndef USART6_485OutDis
#define	USART6_485OutDis	EFDefOutDis
#endif

	// 初始化串口
	switch(usart)
	{
#ifdef COMM_USART1
		case COMM_USART1:
		{
			InitUsart1(baud, dat, parity, stop);		// 串口1
			RegisterEFCommFunc(&g_efCommCtrl[idx], Usart1SendData, Usart1GetData, Usart1CleanRsBuf, IsUsart1SendOver, USART1_485OutEn, USART1_485OutDis);
			break;
		}
#endif
#ifdef COMM_USART2
		case COMM_USART2:
		{
			InitUsart2(baud, dat, parity, stop);		// 串口2
			RegisterEFCommFunc(&g_efCommCtrl[idx], Usart2SendData, Usart2GetData, Usart2CleanRsBuf, IsUsart2SendOver, USART2_485OutEn, USART2_485OutDis);
			break;
		}
#endif
#ifdef COMM_USART3
		case COMM_USART3:
		{
			InitUsart3(baud, dat, parity, stop);		// 串口3
			RegisterEFCommFunc(&g_efCommCtrl[idx], Usart3SendData, Usart3GetData, Usart3CleanRsBuf, IsUsart3SendOver, USART3_485OutEn, USART3_485OutDis);
			break;
		}
#endif
#ifdef COMM_USART4
		case COMM_USART4:
		{
			InitUsart4(baud, dat, parity, stop);		// 串口4
			RegisterEFCommFunc(&g_efCommCtrl[idx], Usart4SendData, Usart4GetData, Usart4CleanRsBuf, IsUsart4SendOver, USART4_485OutEn, USART4_485OutDis);
			break;
		}
#endif
#ifdef COMM_USART5
		case COMM_USART5:
		{
			InitUsart5(baud, dat, parity, stop);		// 串口5
			RegisterEFCommFunc(&g_efCommCtrl[idx], Usart5SendData, Usart5GetData, Usart5CleanRsBuf, IsUsart5SendOver, USART5_485OutEn, USART5_485OutDis);
			break;
		}
#endif
#ifdef COMM_USART6
		case COMM_USART6:
		{
			InitUsart6(baud, dat, parity, stop);		// 串口6
			RegisterEFCommFunc(&g_efCommCtrl[idx], Usart6SendData, Usart6GetData, Usart6CleanRsBuf, IsUsart6SendOver, USART6_485OutEn, USART6_485OutDis);
			break;
		}
#endif
		default:
		{
			break;
		}

	}

	g_efCommCtrl[idx].CommOutDis();		// 关闭发送
}

int EFTx(int idx, u8 addr, u16 data, int steps)
{
	int i, timeout, result;
	u8 pSDat[3];

	if ( ((addr & 0xF0) != 0xE0) && ((addr & 0xF0) != 0xF0) )
	{
		return -1;
	}

	if (steps == 1 || steps == -1)
	{
		g_efCommCtrl[idx].CommOutEn();			// 打开发送

		if (steps == -1)
		{
			DelayUs(100);
		}
	}

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

		pSDat[i++] = addr;

		if ((addr & 0xF0) == 0xF0)
		{
			pSDat[i++] = HIBYTE(data);
			pSDat[i++] = LOBYTE(data);
		}
		else
		{
			pSDat[i++] = data;
		}

		g_efCommCtrl[idx].EFCommSend(pSDat, i);
	}

	if (steps == 3)
	{
		if (g_efCommCtrl[idx].IsEFCommSendOver() != TRUE)
		{
			return 0;
		}
	}
	else if (steps == -1)	// 同步发送
	{
		timeout = (i*2 + 4) * g_efCommCtrl[idx].efSendWait;	// 超时时间,单位us((字节数*2 + 4) * 每个字节发送时长)

		do	//等待发送完成
		{
			if (g_efCommCtrl[idx].IsEFCommSendOver() == TRUE)
			{
				break;
			}

			DelayUs(1);

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

		DelayUs(g_efCommCtrl[idx].efSendWait);	// 等待最后一个字节发送完成

	}

	if (steps == 4 || steps == -1)
	{
		g_efCommCtrl[idx].EFCommCleanRsBuf();	// 清空已接收的数据
		g_efCommCtrl[idx].CommOutDis();				// 关闭发送
	}

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

	return result;

}

int EFRx(int idx, u16 * pData, int steps)
{
	int exlen, timeout, result;
	u8 pRDat[3];

	if (pData == NULL || (steps != 1 && steps != -1))
	{
		return -1;
	}

	memset(pRDat, 0, 3);

	exlen = 3;
	timeout = exlen*2 + 200;	// 超时时间

	do
	{
		result = g_efCommCtrl[idx].EFCommReceive(pRDat, exlen);	// 从缓冲区读取数据
		if (result >= exlen)
		{
			// 处理数据包

			if (pRDat[0] != 0xE0)
			{
				result = -4;		// 接收错误
				break;
			}

			*pData = MAKEWORD(pRDat[2], pRDat[1]);

			break;
		}
		else if (result < 0)
		{
			if (result == -2)	// 串口没有初始化
			{
				printf("usart is not inited\r\n");
			}
			else if (result == -3)	// 接收缓冲区控制错误
			{
				printf("usart receive buf ctrl error\r\n");
			}
			break;
		}

		if (steps == -1)
		{
			// 等待接收完成
			DelayUs(g_efCommCtrl[idx].efSendWait);

			if (timeout-- <= 0)
			{
				printf("2. call EFRx timeout\r\n");
				result = -5;		//接收超时
				break;
			}
		}
		else
		{
			result = 0;
			break;
		}

	}while(1);

	return result;
}

int EFComm(int idx, u8 addr, u16 wrDat, u16 * pRdBuf)
{
	int result;

	result = EFTx(idx, addr, wrDat, -1);

	if (result == 0)
	{
		// 等待回包
		if (addr == 0xE0 && wrDat >= 32 && wrDat <= 63)
		{
			if (pRdBuf != NULL)
			{
				result = EFRx(idx, pRdBuf, -1);
			}
		}
	}

	return result;
}

AsyncEFCtrl g_asyncefCtrl[EF_NUM];

void InitAsyncEFCtrl(int idx, int rsvtimout)
{
	memset(&g_asyncefCtrl[idx], 0, sizeof(AsyncEFCtrl));

	// 读取超时时间
	if (rsvtimout < 20)
	{
		g_asyncefCtrl[idx].efrsvTimout = 20;
	}
	else if (rsvtimout > 200)
	{
		g_asyncefCtrl[idx].efrsvTimout = 200;
	}
	else
	{
		g_asyncefCtrl[idx].efrsvTimout = rsvtimout;
	}
}

void RegEFCmdProc(int idx, ResvEFProc proc)
{
	g_asyncefCtrl[idx].resvefproc = proc;
}

int AddEFCmd(EFCmd * pCmd)
{
	if (pCmd != NULL)
	{
		AsyncEFCtrl * p485Ctrl = &g_asyncefCtrl[pCmd->idx];

		if (p485Ctrl != NULL)
		{
			if (p485Ctrl->bufCmdNum < MAX_EF_CMD && p485Ctrl->bufTail < MAX_EF_CMD)
			{
				memcpy(&(p485Ctrl->cmdbuf[p485Ctrl->bufTail]), pCmd, sizeof(EFCmd));
				p485Ctrl->bufTail++;
				if (p485Ctrl->bufTail >= MAX_EF_CMD)
				{
					p485Ctrl->bufTail = 0;
				}
				p485Ctrl->bufCmdNum++;
				return p485Ctrl->bufCmdNum;
			}
			else
			{
				printf("ef %d cmd buff full\r\n", pCmd->idx);
				return -2;
			}
		}
		return -1;
	}

	return -1;
}

int GetEFCmdBufLen(int idx)
{
	return g_asyncefCtrl[idx].bufCmdNum;
}

int AsyncEFTask(int idx)
{
	// 分步骤执行
	int rslt;
	u32 curIime;

	EFCmd *pCmd;

	AsyncEFCtrl * p485Ctrl = &g_asyncefCtrl[idx];

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

	pCmd = &(p485Ctrl->cmdbuf[p485Ctrl->bufHead]);

	// 读取当前时间
	curIime = GetUsSoftTimer();

	if ((curIime - p485Ctrl->stepTime) > g_efCommCtrl[pCmd->idx].efSendWait)
	{
		p485Ctrl->stepTime = curIime;

		if (p485Ctrl->working == 0 &&
			p485Ctrl->bufCmdNum > 0 &&
			p485Ctrl->steps == 0)
		{
			p485Ctrl->working = 1;
			p485Ctrl->steps = 1;
		}

		if (p485Ctrl->working == 0)
		{
			p485Ctrl->steps = 0;
			return 0;
		}

		if (p485Ctrl->steps > 0 && p485Ctrl->steps < 5)
		{
			rslt = EFTx(pCmd->idx, pCmd->addr, pCmd->wrdat, p485Ctrl->steps);

			if (rslt == p485Ctrl->steps)
			{
				p485Ctrl->steps++;
			}
		}
		else if (p485Ctrl->steps >= 5 && p485Ctrl->steps < p485Ctrl->efrsvTimout)
		{
			// 等待回包
			if (pCmd->addr == 0xE0 && pCmd->wrdat >= 32 && pCmd->wrdat <= 63)
			{
				rslt = EFRx(pCmd->idx, &pCmd->rddat, 1);
				if (rslt == 3)	// 读到正确数据
				{
					// 执行读到数据函数
					if (p485Ctrl->resvefproc != NULL)
					{
						p485Ctrl->resvefproc(pCmd);
					}
					p485Ctrl->steps = p485Ctrl->efrsvTimout;
				}
				else
				{
					p485Ctrl->steps++;
				}
			}
			else
			{
				p485Ctrl->steps = p485Ctrl->efrsvTimout;
			}
		}
		else
		{
			p485Ctrl->steps++;
		}

		if (p485Ctrl->steps >= p485Ctrl->efrsvTimout)
		{
			if (p485Ctrl->bufCmdNum > 0)
			{
				p485Ctrl->bufCmdNum--;
			}
			p485Ctrl->steps = 0;
			p485Ctrl->working = 0;
			p485Ctrl->bufHead++;
			if (p485Ctrl->bufHead >= MAX_EF_CMD)
			{
				p485Ctrl->bufHead = 0;
			}
		}
	}
	return p485Ctrl->steps;
}

