
#define _IN_COMM_C
#include "comm.h"
#include "crc16.h"


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

// 读空缓冲区
// 读空缓冲区
int ReadBuffEmpty(DataExFuns * funs)
{
	int rslt, len;
	int rdlen;
#define	ONCE_READ		16
	u8 tempbuf[ONCE_READ];

	len = funs->GetRsvLen();

	while (len > 0)
	{
		if (len < ONCE_READ)
		{
			rdlen = len;
		}
		else
		{
			rdlen = ONCE_READ;
		}
		rslt = funs->GetCommData(tempbuf, rdlen);

		if (rslt <= 0)
		{
			rslt = 0;
			break;
		}
		len -= rslt;
	}
	return len;
}

//--------------------------------------------------------------------------------------------------
// 功能: 从通讯口接收缓冲区中得到一个数据包,
//		 只能取得普通数据包结构. 如果数据包还有附加数据, 那么需要用 GetExCommData 函数取得
// 参数: pPacket, 数据包指针
// 返回: >=0, 成功取得一个数据包，包括定长数据包和可变长度数据包，返回值为数据包长度
//		 -1, 参数错误
//		 -2, CRC错误
//		 -3, 数据不足
//		 -4, 没有找到同步序列
//		 -5，等待接收数据超时
//		 -6, 数据包参数错误
//		 -7, 附加数据CRC错误
// 		 -8, 发生未知错误

// 结果: 如果正确取得数据包，或通讯口没有命令, 循环队列尾指针回向后移动

#define	MAX_TCP_PACKET	1500


typedef struct
{
	int len;										// 已读取数据长度
	u8 buff[LEN_NORMAL_PACKET+MAX_TCP_PACKET];		// 接收缓冲区

}GetPacketCtrl;

GetPacketCtrl g_gtpCtrl = {0};

#define	MAX_ONCE_SCAN	(LEN_NORMAL_PACKET)		// 一次扫描最大字节数

/*
 * return: -1,参数错误
 * 		   -2,CRC校验错误
 * 		   -3,没有足够的数据
 */
int GetANormalPacket(DataExFuns * funs, DataPacket * pPacket)
{
	int rslt, len;
	int i;
	int phase;
	int status;		// 同步序列		1,FLDP		2,VLDP
	int exlen;
	int begidx;

	u8 temp;
	u8 rdBuf[LEN_NORMAL_PACKET];
	DataPacket * pDat = (DataPacket *)(rdBuf);

	if (funs == NULL || pPacket == NULL)
	{
		return -1;
	}

	// 读取一次数据包到缓冲区
	if (g_gtpCtrl.len < LEN_NORMAL_PACKET + MAX_EXDP_LEN)
	{
		len = funs->GetRsvLen();		// 读取已接收数据长度

		if (len <= 0)
		{
			rslt = -3;	// 没有足够数据
		}
		else
		{
			if (len + g_gtpCtrl.len <= MAX_TCP_PACKET)
			{
				rslt = funs->GetCommData(&(g_gtpCtrl.buff[g_gtpCtrl.len]), len);		// 读取一段数据
			}
			else
			{
//				printf("Get a big packet, len=%d\r\n", len);
				rslt = funs->GetCommData(&(g_gtpCtrl.buff[g_gtpCtrl.len]), MAX_TCP_PACKET-g_gtpCtrl.len);		// 读取一段数据
			}

			g_gtpCtrl.len += rslt;	// 实际数据长度增加
//			printf("load a packet to buff, len=%d, buflen=%d\r\n", len, g_gtpCtrl.len);
		}
	}

	len = g_gtpCtrl.len;
	if (len < LEN_NORMAL_PACKET)
	{
		rslt = -3;
		return rslt;	// 没有足够数据
	}

	i = 0;				// 扫描字节计数器
	begidx = 0;			// 正确数据包起始计数器
	phase = 0;
	status = 0;
	rslt = 0;

	while(phase < LEN_NORMAL_PACKET)
	{
		if (phase == 0 && i > MAX_ONCE_SCAN)
		{
			rslt = -4;
			break;		// 查找同步序列超出最大单次扫描字节数
		}

		if (i < g_gtpCtrl.len)
		{
			temp = g_gtpCtrl.buff[i];
			i++;				// 扫描字数增加
		}
		else
		{
//			printf("data not enough\r\n");
			rslt = -3;		// 数据不足
			break;
		}

		pDat->buff.normal[phase] = temp;	// 保存数据
		if (phase < DP_SYNC_LEN)			// 识别同步序列
		{
			if (phase == 0)
			{
				if (temp == FLDP_SYNC[0])
				{
					begidx = i-1;
					status = 1;
				}
				else if (temp == VLDP_SYNC[0])
				{
					begidx = i-1;
					status = 2;
				}
				else
				{
					begidx = i;
					status = 0;
					phase = 0;
					rslt = 0;		// 非同步序列，继续扫描
					continue;
				}
			}
			else
			{
				if (status == 1)
				{
					if (temp != FLDP_SYNC[phase])		// 同步序列不正确，继续扫描
					{
						begidx = 0;
						status = 0;
						phase = 0;
						rslt = 0;
						continue;
					}
				}
				else if (status == 2)
				{
					if (temp != VLDP_SYNC[phase])		// 同步序列不正确，继续扫描
					{
						begidx = 0;
						status = 0;
						phase = 0;
						rslt = 0;
						continue;
					}
				}
				else
				{
					begidx = 0;
					status = 0;
					phase = 0;
					rslt = -8;
					printf("1. error status in GetANormalPacket\r\n");
					break;
				}
			}
		}
		phase++;
	}

	if (phase >= LEN_NORMAL_PACKET)		// 得到数据包
	{
		u16 crc;
		crc = CalcCrc16(pDat->normal.content, DP_CONT_LEN);
		if (crc == pDat->normal.crc)
		{
			// 得到正确数据包
			memcpy(pPacket, pDat, LEN_NORMAL_PACKET);
//			printf("GetANormalPacket ok\r\n");
			rslt = LEN_NORMAL_PACKET;
		}
		else
		{
			// CRC 不正确
			begidx = i;
			printf("2. crc error in GetANormalPacket\r\n");
			rslt = -2;
		}
	}

	if (rslt == LEN_NORMAL_PACKET)		// 正确得到
	{
		if (memcmp(pPacket->normal.sync, VLDP_SYNC, DP_SYNC_LEN) == 0)	// 是可变长度数据包 vldp
		{
			// 附加数据
			exlen = pPacket->vldp.exlen;
			if (exlen > MAX_EXDP_LEN)
			{
				begidx += LEN_NORMAL_PACKET+exlen;
				printf("data exlen error, len=%d\r\n", exlen);
				rslt = -6;	// 数据包参数错误
			}
			else if (exlen == 0)
			{
				begidx += LEN_NORMAL_PACKET;
				rslt = LEN_NORMAL_PACKET;
			}
			else if (exlen + LEN_NORMAL_PACKET > g_gtpCtrl.len)
			{
				// 数据不足, 暂时退出
			//	printf("exdata not enough, exlen=%d, g_gtpCtrl.len=%d\r\n", exlen, g_gtpCtrl.len);
				rslt = -3;	// 数据不足
			}
			else
			{
				// 20240606 ljs 修复拷贝数据时的地址错误
#if (1)
				// 增加扩展数据CRC校验(1k字节校验耗时约1ms)
				u16 crc;
				crc = CalcCrc16(&g_gtpCtrl.buff[i], exlen);
				if (crc == pDat->vldp.excrc)
				{
					memcpy(pPacket->buff.exData, &(g_gtpCtrl.buff[i]), exlen);	// 拷贝数据
					if (exlen < MAX_EXDP_LEN)
					{
						pPacket->buff.exData[exlen] = 0;
					}
					rslt = LEN_NORMAL_PACKET+exlen;
				}
				else
				{
					printf("3. excrc error in GetANormalPacket\r\n");
					rslt = -2;
				}
				begidx += LEN_NORMAL_PACKET+exlen;
#else
				begidx += LEN_NORMAL_PACKET+exlen;
				memcpy(pPacket->buff.exData, &(g_gtpCtrl.buff[i]), exlen);	// 拷贝数据
				if (exlen < MAX_EXDP_LEN)
				{
					pPacket->buff.exData[exlen] = 0;
				}
				rslt = LEN_NORMAL_PACKET+exlen;
#endif
			}
		}
		else
		{
			begidx += LEN_NORMAL_PACKET;		// 固定长度数据包
		}
	}

	// 拷贝剩余数据到最前端
	if (begidx > 0 && begidx <= g_gtpCtrl.len)
	{
		if (begidx < g_gtpCtrl.len)
		{
	//		printf("copy data, begidx=%d, len=%d\r\n", begidx, (g_gtpCtrl.len - begidx));
			memcpy(&(g_gtpCtrl.buff[0]), &g_gtpCtrl.buff[begidx], (g_gtpCtrl.len - begidx));
		}
		g_gtpCtrl.len -= begidx;
		begidx = 0;
	}
	else if (begidx < 0)
	{
		printf("beginidx < 0\r\n");		
	}
	else if (begidx > g_gtpCtrl.len)
	{
		g_gtpCtrl.len = 0;
		printf("begidx=%d > g_gtpCtrl.len=%d, set g_gtpCtrl.len = 0\r\n", begidx, g_gtpCtrl.len);
	}
	else
	{
	}

	return rslt;
}

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

// 功能: 添加数据到发送队列中, 通过通讯口发送数据
// 参数: pPacket, 需要发送的数据，已经正确存放在了相应字段。
// 结果:
//		 0, 可以发送, 添加到了发送数据队列中
//		 -1, 参数错误
//		 -2，发送错误
//		 1, 队列已满, 不能发送
int SendAPacket(DataExFuns * funs, DataPacket * pPacket, int waittime)
{
	int rslt;
	int freelen, sendlen;

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

	if (memcmp(pPacket->normal.sync, FLDP_SYNC, DP_SYNC_LEN) == 0)
	{
		sendlen = LEN_NORMAL_PACKET;
	}
	else if (memcmp(pPacket->normal.sync, VLDP_SYNC, DP_SYNC_LEN) == 0)
	{
		sendlen = LEN_NORMAL_PACKET + pPacket->vldp.exlen;
	}
	else
	{
		printf("para err, not a corrected packet\r\n");
		return -1;
	}

	rslt = 0;
	do
	{
		freelen = funs->GetTrsFreeLen();
		if (freelen <= 0)	// 可能网络未连接
		{
		//	printf("error at call GetTrsFreeLen, freelen=%d\r\n", freelen);
			rslt = -2;
			break;
		}
		if (freelen >= sendlen)
		{
			break;
		}

		waittime--;
		if (waittime <= 0)
		{
			rslt = 1;
//			printf("buff is full in SendAPacket, timout\r\n");
			break;
		}
		if (funs->Delay != NULL)
		{
			funs->Delay(1);
		}
	}while(1);

	if (rslt == 0)
	{
		rslt = funs->SendCommData(pPacket->datbuff, sendlen);
		if (rslt != sendlen)
		{
			printf("error at call SendCommData, rslt=%d\r\n", rslt);
			return -2;
		}
	}
	else
	{
		//printf("error:Not SendCommData\r\n");
	}

	return 0;
}

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

// 功能: 打包一个固定长度数据包
// 参数:
//		 pPacket, 需要打包的数据包，其中除了sync和crc的部分已经就绪
// 结果:
//		 0, 打包好数据
//		 -1, 参数错误

int PacketAFLDP(DataPacket * pPacket)
{
	if (pPacket == NULL)
	{
		return -1;
	}

	memcpy(pPacket->normal.sync, FLDP_SYNC, DP_SYNC_LEN);
	pPacket->normal.crc = CalcCrc16(pPacket->normal.content, DP_CONT_LEN);

	return 0;
}

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

// 功能: 打包一个可变长度数据包
// 参数: pPacket, 需要打包的数据包，需要填充其中的 SYNC EXLEN EXCRC 和 EXDAT 等部分
//		 pExdat, 附加数据，可以为空
//		 exlen，附加数据长度，可以为0
// 结果:
//		 0, 打包好数据
//		 -1, 参数错误
//		 -2，

int PacketAVLDP(DataPacket * pPacket, const u8 * pExdat, u16 exlen)
{
	if (pPacket == NULL)
	{
		return -1;
	}

	if (pExdat == NULL)
	{
		exlen = 0;
	}

	memcpy(pPacket->vldp.sync, VLDP_SYNC, DP_SYNC_LEN);
	pPacket->vldp.exlen = exlen;
	pPacket->vldp.excrc = CalcCrc16(pExdat, exlen);
	pPacket->vldp.crc = CalcCrc16(pPacket->normal.content, DP_CONT_LEN);
	if (exlen != 0 && pPacket->vldp.exData != pExdat)
	{
		memcpy(pPacket->vldp.exData, pExdat, exlen);
	}
	return 0;
}

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


