
#define _IN_MTCOMM_C
#include "mtcomm.h"
#include "crc8.h"
#include "trigger.h"

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


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

typedef struct
{
	MtCommExFuncs commExFuncs;		// 交换函数

	MtCommPacket sendPacket;		// 发送的数据包
	MtCommPacket resvPacket;		// 接收的数据包

	// 传输过程控制
	int transEnable;		// 传输允许, 0, 不允许; 1, 发送允许； 2， 接收允许
	int transId;			// 当前传输ID

	int sendStatus;			// 发送状态, 0, 空闲; 1, 发送中; 2，接收回包中; 3, 完成。
	int sendResult;			// 发送结果, 0， 正常空闲； 1，发送成功； 2， 发送失败； 3，等待回包成功，4，  等待回包超时
	int sendSteps;			// 发送控制步骤

	int hasBack;			// 是否有回包（会自动等待回包）

	int resvStatus;			// 接收状态， 0， 空闲;  1, 等待接收中;  2, 收到数据包; 3. 接收停止

	u32 ustimer;

}MtCommCtrl;


MtCommCtrl g_mtCommCtrl;

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


// 初始化
// 注册收发函数和485开关函数
void InitMtComm(MtCommExFuncs * pExFuncs)
{
	memset(&g_mtCommCtrl, 0, sizeof(MtCommCtrl));

	if (pExFuncs != NULL)
	{
		memcpy(&(g_mtCommCtrl.commExFuncs), pExFuncs, sizeof(MtCommExFuncs));
	}
}

// 异步收发过程,完成数据的收发过程。
// 需要在控制流程中不停调用
void MtCommAsyncTask(void)
{
	if (g_mtCommCtrl.transEnable == 1)		// 发送允许
	{
		switch (g_mtCommCtrl.sendSteps)
		{
			case 0:
				g_mtCommCtrl.sendStatus = 1;		// 传输中
				g_mtCommCtrl.sendResult = 0;
				g_mtCommCtrl.sendSteps++;
				break;
			case 1:		// 打开发送允许
			{
				if (g_mtCommCtrl.commExFuncs.Set485TxEnOn != NULL)
				{
					g_mtCommCtrl.commExFuncs.Set485TxEnOn();	// 发送允许打开
				}
				g_mtCommCtrl.ustimer = GetUsSoftTimer();
				g_mtCommCtrl.sendSteps++;
				break;
			}
			case 2:		// 等待发送允许生效, 开始发送数据包
			{
				u32 thisus;
				thisus = GetUsSoftTimer();
				if (thisus - g_mtCommCtrl.ustimer > 200)
				{
					if (g_mtCommCtrl.commExFuncs.SendMtCommData != NULL)
					{
						g_mtCommCtrl.commExFuncs.SendMtCommData((u8*)&g_mtCommCtrl.sendPacket, LEN_MTCOMM_PKT);	// 发送数据
					}

					g_mtCommCtrl.sendSteps++;
				}
				break;
			}
			case 3:		// 等待发送完成
			{
				int freelen = 0;
				if (g_mtCommCtrl.commExFuncs.GetTrsFreeLen != NULL)
				{
					freelen = g_mtCommCtrl.commExFuncs.GetTrsFreeLen();
				}
				if (freelen <= 0)
				{
					g_mtCommCtrl.ustimer = GetUsSoftTimer();
					g_mtCommCtrl.sendSteps++;
				}
				break;
			}
			case 4:		// 等待最后一个发送完成, 关闭发送允许
			{
				u32 thisus;
				thisus = GetUsSoftTimer();
				if (thisus - g_mtCommCtrl.ustimer > 200)
				{
					if (g_mtCommCtrl.commExFuncs.Set485TxEnOff != NULL)
					{
						g_mtCommCtrl.commExFuncs.Set485TxEnOff();	// 发送允许关闭
					}
					g_mtCommCtrl.sendSteps++;
				}
				break;
			}

			case 5:
			{
				if (g_mtCommCtrl.hasBack != 0)			// 如果有回包
				{
					g_mtCommCtrl.sendStatus = 2;		// 等待回包状态
					g_mtCommCtrl.ustimer = GetUsSoftTimer();	// 记录时间点

					g_mtCommCtrl.resvStatus = 0;
					g_mtCommCtrl.transEnable = 2;		// 启动接收
				}
				else
				{
					g_mtCommCtrl.sendStatus = 3;		// 传输完成
					g_mtCommCtrl.sendResult = 1;		// 发送成功
					g_mtCommCtrl.transEnable = 0;		// 不允许传输
				}
				break;
			}
			default:
			{
				g_mtCommCtrl.sendStatus = 3;		// 传输完成
				g_mtCommCtrl.sendResult = 2;		// 发送失败
				g_mtCommCtrl.transEnable = 0;		// 不允许传输
				break;
			}
		}
	}
	else if (g_mtCommCtrl.transEnable == 2)	// 接收允许
	{
		int rsvlen = 0;

		g_mtCommCtrl.resvStatus = 1;	// 接收数据中
		if (g_mtCommCtrl.commExFuncs.Set485TxEnOff != NULL)	// 关闭发送允许
		{
			g_mtCommCtrl.commExFuncs.Set485TxEnOff();	// 发送允许关闭
		}

		if (g_mtCommCtrl.commExFuncs.GetMtRsvLen != NULL)
		{
			rsvlen = g_mtCommCtrl.commExFuncs.GetMtRsvLen();	// 得到已接收数据长度
		}
		if (rsvlen >= LEN_MTCOMM_PKT)	// 数据长度够
		{
			if (g_mtCommCtrl.commExFuncs.GetMtCommData != NULL)
			{
				g_mtCommCtrl.commExFuncs.GetMtCommData((u8*)&g_mtCommCtrl.resvPacket, LEN_MTCOMM_PKT);	// 接收数据
			}

			if (g_mtCommCtrl.hasBack != 0)		// 如果有回包
			{
				g_mtCommCtrl.hasBack = 0;
				g_mtCommCtrl.sendStatus = 3;		// 传输完成
				g_mtCommCtrl.sendResult = 3;		// 结果正确
			}
			g_mtCommCtrl.resvStatus = 2;				// 收到数据包
			g_mtCommCtrl.ustimer = GetUsSoftTimer();	// 记录时间点
			g_mtCommCtrl.transEnable = 0;			// 关闭传输
		}
		else
		{
			if (g_mtCommCtrl.hasBack != 0)		// 如果有回包
			{
				u32 thisus;
				thisus = GetUsSoftTimer();
				if (thisus - g_mtCommCtrl.ustimer > 10000)	// 10ms 超时
				{
					g_mtCommCtrl.resvStatus = 3;		// 接收停止

					g_mtCommCtrl.hasBack = 0;
					g_mtCommCtrl.sendStatus = 3;		// 传输完成
					g_mtCommCtrl.sendResult = 4;		// 结果超时
					g_mtCommCtrl.transEnable = 0;		// 关闭传输
				}
			}
			else
			{
				// 继续等待
			}
		}
	}
	else	// 其他情况, 什么也不做
	{
	}
}

// 打包一个数据包
// 添加同步字，生成CRC
int PacketAMtComm(MtCommPacket * pPacket)
{
	if (pPacket == NULL)
	{
		return -1;
	}

	memcpy(pPacket->sync, MTCOMM_SYNC, MT_SYNC_LEN);
	pPacket->crc8 = CalcCrc8((u8*)pPacket, MT_CHECK_LEN);

	return 0;
}

// 校验一个数据包
// 验证同步字和CRC
// 返回0，正常
int CheckAMtPacket(MtCommPacket * pPacket)
{
	int rslt;
	if (pPacket == NULL)
	{
		return -1;
	}
	rslt = memcmp(pPacket->sync, MTCOMM_SYNC, MT_SYNC_LEN);
	if (rslt == 0)
	{
		u8 crc;
		crc = CalcCrc8((u8*)pPacket, MT_CHECK_LEN);
		if (pPacket->crc8 != crc)
		{
			rslt = -2;
		}
	}
	return rslt;
}

// 读空接收buff
void ReadMtCommBuffEmpty(void)
{
	int rslt, len;
	u8 temp;

	len = 0;
	if (g_mtCommCtrl.commExFuncs.GetMtRsvLen != NULL)
	{
		len = g_mtCommCtrl.commExFuncs.GetMtRsvLen();
	}

	while (len > 0)
	{
		if (g_mtCommCtrl.commExFuncs.GetMtCommData != NULL)
		{
			rslt = g_mtCommCtrl.commExFuncs.GetMtCommData(&temp, 1);
		}
		else
		{
			break;
		}
		if (rslt != 1)
		{
			rslt = 0;
			break;
		}
		len--;
	}
}

// 启动一次发送任务
// 返回传输ID
int SendAMtPacket(MtCommPacket * pPacket, int hasback)
{
	if (pPacket == NULL)
	{
		return -1;
	}
	if (g_mtCommCtrl.sendStatus != 0 || g_mtCommCtrl.sendStatus != 3)
	{
		return -2;
	}

	g_mtCommCtrl.transEnable = 0;

	g_mtCommCtrl.sendStatus = 0;
	g_mtCommCtrl.sendResult = 0;
	g_mtCommCtrl.sendSteps = 0;

	// 是否等待回包
	g_mtCommCtrl.hasBack = hasback;

	g_mtCommCtrl.transId++;		// 传输 ID 自增
	if (g_mtCommCtrl.transId < 10 || g_mtCommCtrl.transId > 10000000)
	{
		g_mtCommCtrl.transId = 10;
	}

	memcpy(&g_mtCommCtrl.sendPacket, pPacket, LEN_MTCOMM_PKT);

	g_mtCommCtrl.transEnable = 1;		// 启动接收

	return g_mtCommCtrl.transId;	// 返回当前传输的ID，方便后续查询使用
}

// 获取发送状态
int GetSendStatus(int id)
{
	int sta;
	if (g_mtCommCtrl.transId != id)
	{
		return -1;
	}

	sta = g_mtCommCtrl.sendStatus;
	if (sta == 3)
	{
		g_mtCommCtrl.sendStatus = 0;		// 自动清零
	}
	return sta;
}

// 获取发送结果
int GetSendResult(int id)
{
	if (g_mtCommCtrl.transId != id)
	{
		return -1;
	}

	return g_mtCommCtrl.sendResult;
}


// 读取一个数据包
// 如果接收到， 回包数据在pPacket中
int GetAMtPacket(MtCommPacket * pPacket)
{
	if (g_mtCommCtrl.transEnable != 2)	// 非接收状态
	{
		g_mtCommCtrl.transEnable = 0;

		g_mtCommCtrl.resvStatus = 0;

		ReadMtCommBuffEmpty();

		g_mtCommCtrl.transEnable = 2;		// 启动接收
	}

#define	MAX_MTCOMM_SCAN		128			// 单次最大扫描个数

	if (1)
	{
		int rslt, len;
		int i;
		int phase;

		u8 temp;
		u8 rdBuf[LEN_MTCOMM_PKT];
		MtCommPacket * pDat;

		if (pPacket == NULL ||
			g_mtCommCtrl.commExFuncs.GetMtRsvLen == NULL ||
			g_mtCommCtrl.commExFuncs.GetMtCommData == NULL ||
			0	)
		{
			return -1;
		}

		i = 0;				// 扫描字节计数器
		pDat = (MtCommPacket *)rdBuf;

		do
		{
			len = g_mtCommCtrl.commExFuncs.GetMtRsvLen();

			if (len < LEN_MTCOMM_PKT)
			{
				rslt = -3;
				break;			// 没有足够数据
			}

			phase = 0;
			rslt = 0;

			// 从接收缓冲区中找数据包
			while(((len + phase) >= LEN_MTCOMM_PKT) && (phase < LEN_MTCOMM_PKT))
			{
				if (phase == 0 && i > MAX_MTCOMM_SCAN)
				{
					rslt = -4;
					break;		// 查找同步序列超出最大单次扫描字节数
				}

				rslt = g_mtCommCtrl.commExFuncs.GetMtCommData(&temp, 1);		// 读取一个字节
				if (rslt != 1)
				{
					printf("error at GetMtCommData rslt\r\n");
					rslt = -8;
					break;
				}

				rslt = 0;
				i++;				// 扫描字数增加
				len--;				// 剩余长度减小

				if (phase < MT_SYNC_LEN)			// 识别同步序列
				{
					if (temp != MTCOMM_SYNC[phase])
					{
						phase = 0;
						rslt = 0;
						break;
					}
				}

				rdBuf[phase] = temp;	// 保存
				phase++;
			}

			if (rslt != 0)
			{
				break;
			}

			if (phase >= LEN_MTCOMM_PKT)		// 得到数据包
			{
				u8 crc8;
				crc8 = CalcCrc8(rdBuf, MT_CHECK_LEN);
				if (crc8 == pDat->crc8)
				{
					// 得到正确数据包
					memcpy(pPacket, pDat, LEN_MTCOMM_PKT);
	//				printf("GetAMtCommPacket ok\r\n");
					rslt = LEN_MTCOMM_PKT;
					break;
				}
				else
				{
					// CRC 不正确
					printf("1. crc error in GetAMtCommPacket\r\n");
					// 拷贝需要再判断的数据
	//				continue;
				}
			}
			else
			{
				// 没有找到同步序列的情况
	//			continue;
			}
		}while(1);

		return rslt;
	}
}


