/******************************************************************************
版权所有：	
文件名称：	protocol.c
文件版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-5-5
功能说明：	规约层实现文件
								

-------------------
-				APP层			-
-------------------
-				规约层		-
-------------------
-				通道层		-
-------------------
-				驱动层		-
-------------------
								
								
								
其它说明：
修改记录：
*/
#include  "head.h"
#include "myconf.h"
#include "channel.h"
#include "protocol.h"



//一个帧的缓冲区大小
#define FRM_BUF_SIZE		256
//帧缓冲区个数
#define MAX_BUF_SIZE		8

//1秒计数值
#define PROTOCOL_TIMEOUT		1*USTIMER_SEC


//缓冲区数据结构
struct protocol_buf{
	unsigned char 		cTypeCounter;	
	unsigned char 		cLenth; 			//长度
	unsigned char 		cCnt;					
	unsigned char     src_addr;
	unsigned char     dst_addr;
	unsigned char			sum;
	unsigned char 		arrBuf[FRM_BUF_SIZE];				
};


//全局信息
struct protocol_info{
	struct protocol_buf	txbuf[MAX_BUF_SIZE];
	struct protocol_buf	rxbuf[MAX_BUF_SIZE];
	unsigned char tx_head;
	unsigned char tx_tail;
	unsigned char rx_head;
	unsigned char rx_tail;	
	uint32_t tm;  //接收超时参照时间点, 如果超过1秒没有数据,则认为帧结束
	T_channel  *p_chan; 
	int recvOK;  //在半双工的情况下，recvOK=1表示接受一个完整的数据帧，recvOK=0表示没有收到完整的帧或数据
};


struct protocol_info g_info[PROTOCOL_CHNS];
static int g_chan_cnt = 0; //已经使用的通道数

/******************************************************************************
函数名称：	protocol_reset
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	解包复位处理
参数说明：	
						p_info:全局信息指针

返回值：	无
修改记录：	
*/
static void protocol_reset(struct protocol_info *p_info)
{
	p_info->rxbuf[p_info->rx_head].cTypeCounter = 0;
	p_info->rxbuf[p_info->rx_head].cCnt = 0;
	p_info->rxbuf[p_info->rx_head].sum = 0;	

	p_info->recvOK = 1; //接收完成数据
}
/******************************************************************************
函数名称：	protocol_unpacket
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	解包处理
参数说明：	
						p_info:全局信息指针
						byRevData: 接收的数据

返回值：	无
修改记录：	
*/
static void protocol_unpacket(struct protocol_info *p_info, unsigned char byRevData)
{	
	//将数据放到缓冲区
	p_info->rxbuf[p_info->rx_head].arrBuf[p_info->rxbuf[p_info->rx_head].cCnt++]= byRevData;
 	
	//逐步检查帧的合法性: 启动字符(0x68)+长度+长度+启动字符(0x68)+数据+校验和+结束字符  
	switch(p_info->rxbuf[p_info->rx_head].cTypeCounter)
	{
		case 0:							//检查帧头.第一个启动字符
		if(byRevData==0x68)  
		{
			p_info->rxbuf[p_info->rx_head].cTypeCounter=1;
		}
		else
		{
			//解包复位
			protocol_reset(p_info); 
		}
		break;
		case 1:							//第一个长度
			p_info->rxbuf[p_info->rx_head].cTypeCounter=2;
			p_info->rxbuf[p_info->rx_head].cLenth = byRevData;		
			break;
		case 2:							//第二个长度
			if(p_info->rxbuf[p_info->rx_head].cLenth==byRevData)
			{
				p_info->rxbuf[p_info->rx_head].cTypeCounter=3;
				p_info->rxbuf[p_info->rx_head].cLenth = byRevData+4;
			}
			else
			{
				//解包复位
				protocol_reset(p_info);
			}
			break;
		case 3:							//第二个启动字符
			if(byRevData==0x68)
			{
				p_info->rxbuf[p_info->rx_head].cTypeCounter=4;
				p_info->rxbuf[p_info->rx_head].sum=0;
			}
			else
			{
				//解包复位
				protocol_reset(p_info);
			}
			break;
		case 4:	 						//计算校验和,如果数据读取完毕，下一步进行校验和比较
			p_info->rxbuf[p_info->rx_head].sum+=byRevData;
			if(p_info->rxbuf[p_info->rx_head].cCnt>=p_info->rxbuf[p_info->rx_head].cLenth)
			{
				p_info->rxbuf[p_info->rx_head].cTypeCounter=5;
			}
			break;
		case 5:							//比较校验和		 	
			if(p_info->rxbuf[p_info->rx_head].sum==byRevData)
			{
				p_info->rxbuf[p_info->rx_head].cTypeCounter=6;
			}
			else
			{
				//解包复位
				protocol_reset(p_info);
			}
			break;
		case 6:				
			
			//缓冲区未满
			if(((p_info->rx_head+1) & (MAX_BUF_SIZE - 1)) != p_info->rx_tail)
			{
				//调整缓冲区下标
				p_info->rx_head = (p_info->rx_head+1) & (MAX_BUF_SIZE - 1);
			}
		//	else
			{
				//缓冲区满，丢弃该帧数据
				//解包复位
				protocol_reset(p_info);
			}

			// 唤醒主循环
			mainloop_wakeup();
			
			break;			
		default:   
			//解包复位
			protocol_reset(p_info);
		break;
	}		
	
}

/******************************************************************************
函数名称：	protocol_init
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	初始化协议
参数说明：	
						无 

返回值：	无
修改记录：	
*/
void protocol_init(void)
{
	int i=0;
	 g_chan_cnt = 0; 

	memset(g_info, 0, sizeof(g_info));

	//初始化假设已经接收到数据
	for(i=0;i<PROTOCOL_CHNS;i++)
	{ 
		g_info[i].recvOK=1;
	}
}


/******************************************************************************
函数名称：	protocol_packet
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	协议组包函数
参数说明：	
						src: 源数据
						count: 源数据长度
						srcaddr: 源地址
						dstaddr: 目标地址
						dst: 组包后的数据

返回值：	返回组包后的长度
修改记录：	
*/
int protocol_packet(unsigned char *src, int count,  unsigned char srcaddr,  unsigned char dstaddr, unsigned char *dst)
{
	unsigned char i = 0;
	unsigned char checksum = 0;
	unsigned char len = (unsigned char)count;
	unsigned char *p=dst;
	
	*p++ = 0x68;
	*p++ = len;
	*p++ = len;
	*p++ = 0x68;
	
	memcpy(p, src, count);
	p = &dst[4];
	
	for(i=0; i<len; i++)
	{
		checksum += *p++; 	
	}
	
	*p++ = checksum;
	
	*p = 0x80 | (srcaddr << 3) | dstaddr; 	
	
	return (int)(len + 6);
}

/******************************************************************************
函数名称：	protocol_add_chan
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	绑定一个通道.每个通道都可以使用该规约
参数说明：	
						h_obj: 通道指针	

返回值：	成功返回0, 失败返回-1.
修改记录：	
*/
int protocol_add_chan(T_channel *h_obj)
{
	//检查通道是否已经用完
	if(g_chan_cnt >= PROTOCOL_CHNS)
	{
			return -1;
	}

	//通道指针
	g_info[g_chan_cnt].p_chan = h_obj;
	//通道号
	g_info[g_chan_cnt].p_chan->no = g_chan_cnt;
	//通道计数
	g_chan_cnt++;
	
	return 0;
}

/******************************************************************************
函数名称：	protocol_get_oneframe
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	从通道中获取一帧数据
参数说明：	
						h_obj: 通道指针	
						frm_data: 帧数据

返回值：		成功返回0, 失败返回负数.
修改记录：	
*/
int protocol_get_oneframe(T_channel *h_obj, unsigned char *frm_data)
{
	struct protocol_info *p_info = &g_info[h_obj->no];
	
	//检查参数的合法性
	if((!h_obj) || (!frm_data))
	{
		return -1;
	}
	//接收缓冲区没有数据
	if(p_info->rx_head == p_info->rx_tail)
	{
		return -2;
	}
	//拷贝数据
	memcpy(frm_data, p_info->rxbuf[p_info->rx_tail].arrBuf, p_info->rxbuf[p_info->rx_tail].arrBuf[1]+6);
	p_info->rx_tail = (p_info->rx_tail+1) & (MAX_BUF_SIZE - 1);
	
	return 0;
}

/******************************************************************************
函数名称：	protocol_put_oneframe
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	写一帧数据到通道中
参数说明：	
						h_obj: 通道指针	
						frm_data: 帧数据
						count: 帧数据长度

返回值：		成功返回0, 失败返回负数.
修改记录：	
*/
int protocol_put_oneframe(T_channel *h_obj, unsigned char *frm_data, int count)
{
	struct protocol_info *p_info = &g_info[h_obj->no];
	
	//检查参数的合法性
	if((!h_obj) || (!frm_data) || (count==0))
	{
		return -1;
	}
	//缓冲去满
	if(((p_info->tx_head+1) & (MAX_BUF_SIZE - 1)) == p_info->tx_tail)
	{
		return -2;
	}
	//拷贝数据到发送缓冲区
	memcpy(p_info->txbuf[p_info->tx_head].arrBuf, frm_data, count);	
	//要发送的字节总数
	p_info->txbuf[p_info->tx_head].cLenth = count;
	//已经发送的字节数
	p_info->txbuf[p_info->tx_head].cCnt = 0;    
	//调整发送缓冲区的下标
	p_info->tx_head = (p_info->tx_head+1) & (MAX_BUF_SIZE - 1);
	
	return 0;
}

/******************************************************************************
函数名称：	protocol_unpacket_task
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-05
函数说明：	规约处理任务
参数说明：	
						无

返回值：	无
修改记录：	
*/
void protocol_proc_task(s8 chnl)
{
	int i = 0;
	int ret = 0;

	char ch = 0;

	unsigned char cLenth=0; 			//长度
	unsigned char cCnt=0;	
	unsigned char *p = NULL;

	for(i=0; i<g_chan_cnt; i++)
	{

		//从通道读取数据
		ret = channel_read(g_info[i].p_chan, &ch, 1);

		//有数据
		if(ret > 0)
		{
			//解包
			protocol_unpacket(&g_info[i], (unsigned char)ch);

			//接收超时参考点
			g_info[i].tm = ustimer_get_origin();
		}
		else
		{
			//超时无数据
			if(ustimer_get_duration(g_info[i].tm) >= PROTOCOL_TIMEOUT)
			{
				//解包复位
				protocol_reset(&g_info[i]); 
				//接收超时参考点	
				g_info[i].tm = ustimer_get_origin();		
			}
		}

		//noted by sunxi: 20220706 
		//1. 335x是1条报文接收的，所以不需要下面的时间判断。另外，如果有下面的时间判断，
		//	 当面板按键太快，本含数只接收，不发送了。
		//2. 冷火串口接收是1个字节接收的，因而需要确保接收完一帧后，才发送，所以需要下面的时间判断
#ifdef CPU_COLDFIRE	
		if(ustimer_get_duration(g_info[i].tm)<1*USTIMER_MS)
		{
			continue;
		}
#endif	

		//发送缓冲区有帧数据
		if(g_info[i].tx_head != g_info[i].tx_tail)
		{
			if(g_info[i].p_chan->halfduplex)
			{
				if(!g_info[i].recvOK)
				{
					continue;
				}
			}
			
			//数据长度
			cLenth = g_info[i].txbuf[g_info[i].tx_tail].cLenth; 
			//已经发送的字节数
			cCnt= g_info[i].txbuf[g_info[i].tx_tail].cCnt;	
			//要发送的数据首地址
			p=&g_info[i].txbuf[g_info[i].tx_tail].arrBuf[cCnt];
			//本次需要发送的字节数
			cCnt = cLenth - cCnt;
			
			//还有数据要发送
			if(cCnt > 0)
			{
				// 在发送第一个字节前，将485发送允许
				if(g_info[i].txbuf[g_info[i].tx_tail].cCnt == 0)
				{
					RS_Send_Enable(chnl);
				}
				
			
				//发送数据
				ret = channel_write(g_info[i].p_chan, (const char *)p, cCnt);
				//发送出去了
				if(ret > 0)
				{		
					//计算发送了多少字节
					g_info[i].txbuf[g_info[i].tx_tail].cCnt += (unsigned char)ret;
#if 0
					//如果数据发送完毕,则调整发送缓冲区的下标
					if(g_info[i].txbuf[g_info[i].tx_tail].cCnt == g_info[i].txbuf[g_info[i].tx_tail].cLenth)
					{
						//调整发送缓冲区的下标
						g_info[i].tx_tail = (g_info[i].tx_tail+1) & (MAX_BUF_SIZE - 1);
						g_info[i].recvOK=0; //置没有接收数据
					}		
#endif		
				}
				}
			//如果数据发送完毕,则调整发送缓冲区的下标
#if defined (CPU_AM335X) || defined (CPU_FUXI)
			else
#else	
			else if(MCF_UART_USR(chnl) & MCF_UART_USR_TXEMP)
#endif	
			{
				RS_Recv_Enable(chnl);
				//调整发送缓冲区的下标
				g_info[i].tx_tail = (g_info[i].tx_tail+1) & (MAX_BUF_SIZE - 1);
				g_info[i].recvOK=0; //置没有接收数据
			}
		}
		
	}
	
}


