//===================================================================
//文件名称：node.c（node驱动源程序文件）
//===================================================================
#include "node.h"

//PC和PCNode的通信帧。帧头为0xa5,0x06；帧尾为0xb6,0x07
static uint_8 pcnodeFrameHead[2] = {0xa5,0x06}; //帧头
static uint_8 pcnodeFrameTail[2] = {0xb6,0x07}; //帧尾
static uint_8 UART_NO;      //pcnode使用的串口

//Node之间的通信帧。帧头为R；帧尾为F
static uint_8 rfnodeFrameHead = 'R'; //RF发送帧头
static uint_8 rfnodeFrameTail = 'F'; //RF发送帧尾

static uint_8 RF_hdaddr;      //节点地址
static uint_8 RF_Nodeaddr;      //节点地址

//========================内部函数声明==================================
//在函数定义处有详细说明
void sendpcnodeFrame(uint_16 length,uint_8 *data);
uint_8 historyCheck(uint_16 data);
//======================内部函数声明结束================================

//========================对外函数接口==================================
//=====================================================================
//函数名称：pcnode_init
//函数返回： 无
//参数说明： uartNo：pcnode使用的串口； baud：pcnode的波特率。
//功能概要：初始化pcnode
//更新记录：20190225,ZYL
//=====================================================================
void pcnode_init(uint_8 uartNo,uint_32 baud)
{
	uart_init(uartNo,baud);
	uart_enable_re_int(uartNo);
	UART_NO = uartNo;
}

//=====================================================================
//函数名称：pcnode_send1
//函数返回： 无
//参数说明： a：待发送的一个字节数据
//功能概要：通过pcnode发送一个字节数据
//更新记录：20190225,ZYL
//=====================================================================
void pcnode_send1(uint_8 a)
{
	sendpcnodeFrame(1,&a);
}

//=====================================================================
//函数名称：pcnode_sendN
//函数返回： 无
//参数说明： len：待发送数组的长度；buff：待发送数据缓冲区
//功能概要：通过pcnode发送一个字节数组
//更新记录：20190225,ZYL
//=====================================================================
void pcnode_sendN(uint_8 len ,uint_8* buff)
{
	sendpcnodeFrame(len,buff);
}

//=====================================================================
//函数名称：pcnode_send_string
//函数返回： 无
//参数说明： buff：待发送的字符串
//功能概要：通过pcnode发送一个字符串
//更新记录：20190225,ZYL
//=====================================================================
void pcnode_send_string(uint_8 * buff)
{
	uint_16 len=0;
	while(buff[len])len++;
	sendpcnodeFrame(len,buff);
}

//===========================================================================
//函数名称：pcnode_recv
//功能概要：组建数据帧，将待组帧数据加入到数据帧中。本函数应被放置于中断中。
//参数说明：ch：串口中断接收到的一个字节的串口数据；data：存放接收到的数据。
//函数返回：0：未接收到数据；非0：接收到一帧长度组帧成功，且返回值为接收到的数据长度
//备注：十六进制数据帧格式
//        帧头       + 数据长度         + 有效数据    +  帧尾
//        pcnodeFrameHead   +   len(2个字节)   + 有效数据     +  pcnodeFrameTail
//===========================================================================
uint_16 pcnode_recv(uint_8 ch, uint_8 *data)
{
	static uint_16 index = 0;
	static uint_16 length = 0;
	uint_16 ret_val;
	uint_16 i;
	uint_8 CRC[2];
	uint_16 crc;
	if((index == 0 && ch != pcnodeFrameHead[0]) ||
			(index == 1 && ch != pcnodeFrameHead[1]))//未接收到数据或者未遇到帧头
	{
		index = 0;
		length = 0;
		ret_val = 0;     //接收数据错误
		goto uecom_recv_exit;
	}
	data[index++] = ch;//存入数据
	if(index == 4)//读取有效数据长度
	{
		length = ((uint_16)data[2]<<8) + data[3];
	}
	if(length != 0 && index >= length+6)//接收到的数据达到一帧长度。
	{
		if(data[index-2]!=pcnodeFrameTail[0] || data[index-1]!= pcnodeFrameTail[1])//帧尾检验错误
		{
			index = 0;
			length = 0;
			ret_val = 0;
			goto uecom_recv_exit;
		}
		for(i=0;i<length;i++)
		{
			data[i] = data[i+4];
		}
		index = 0;
		ret_val = length;
		data[length] = 0;
		//若是上位机搜寻设备则自动回发
		if(length == 10 &&
			!strcmp(data,"Whoareyou?"))
		{
			sendpcnodeFrame(6,"PCNode");
			ret_val = 0;
		}
		length = 0;
		goto uecom_recv_exit;
	}
	ret_val = 0;
uecom_recv_exit:
    return ret_val;
}

//=====================================================================
//函数名称：rfnode_init
//函数返回： 无
//参数说明： hdaddr:rfnode的硬件地址;nodeaddr:rfnode的节点地址
//功能概要：初始化rfnode
//更新记录：20190225,ZYL
//=====================================================================
void rfnode_init(uint_8 hdaddr,uint_8 nodeaddr)
{
	RF_hdaddr = hdaddr;
	RF_Nodeaddr = nodeaddr;
    RF_Init(RF_hdaddr);//RF模块初始化
}

//=====================================================================
//函数名称：rfnode_send1
//函数返回： 无
//参数说明： a：待发送的一个字节数据
//功能概要：通过rfnode发送一个字节数据
//更新记录：20190225,ZYL
//=====================================================================
void rfnode_send1(uint_8 a)
{

}

//=====================================================================
//函数名称：rfnode_sendN
//函数返回： 无
//参数说明： len：待发送数组的长度；buff：待发送数据缓冲区
//功能概要：通过rfnode发送一个字节数组
//更新记录：20190225,ZYL
//=====================================================================
void rfnode_sendN(uint_8 len ,uint_8* buff)
{
	//局部变量声明
	uint_8 i,length;
	uint_8 rfsend[64];

	length = len;

	//组帧
	//帧头
	rfsend[0] = rfnodeFrameHead;
    //有效数据长度
	rfsend[1] = length;
    //有效数据
	for(i=2;i<length+2;i++)
	{
		rfsend[i] = buff[i-2];
	}
    //帧尾
	rfsend[length+2] = rfnodeFrameTail;

	length = length + 3;

	RFSendDataByCSMACA(length,&rfsend[0],0,RF_hdaddr);
}

//=====================================================================
//函数名称：rfnode_send_string
//函数返回： 无
//参数说明： buff：待发送的字符串
//功能概要：通过rfnode发送一个字符串
//更新记录：20190225,ZYL
//=====================================================================
void rfnode_send_string(uint_8 * buff)
{

}

//===========================================================================
//函数名称：rfnode_recv
//功能概要：组建数据帧，将待组帧数据加入到数据帧中。本函数应被放置于中断中。
//参数说明：ch：串口中断接收到的一个字节的串口数据；data：存放接收到的数据。
//函数返回：0：成功接收数据并转发；1：接收成功并应答；2：接收成功并接收应答
//函数返回：3：接收无效
//备注：十六进制数据帧格式
//        帧头       + 数据长度         + 有效数据    +  帧尾
//        rfnodeFrameHead   +   len(2个字节)   + 有效数据     +  rfnodeFrameTail
//===========================================================================
uint_8 rfnode_recv(uint_8 *datalen, uint_8 *data)
{
	//局部变量声明
	uint_8 rfbuf[64];
	uint_8 i;
	uint_8 rflen;
	uint_8 flag;

//	static uint_8 history;

	//接受RF数据
	if(0 != RF_ReceiveFrame(rfbuf,&rflen,RF_hdaddr))
	{
		return 3;
	}

	rflen = rfbuf[1];

	//解帧
	if((rfbuf[0] != rfnodeFrameHead)|| (rfbuf[rflen+2] != rfnodeFrameTail))
	{
		return 3;
	}

	for(i=0;i<rflen;i++)
	{
		data[i] = rfbuf[i+2];
	}

	*datalen = rflen;

	flag = historyCheck((rfbuf[rflen+3]<<8)+rfbuf[rflen+4]);
	if(!flag)
	{
		//判断是否是本节点数据，接收应答
		if((data[0]==RF_Nodeaddr)&&(data[5]=='B'))
			return 2;
		//判断是否是本节点数据，需要应答
		else if((data[0]==RF_Nodeaddr)&&(data[5]=='A'))
			return 1;
		else
			return 0;
	}
	else
		return 3;
}

//==========================以下为内部函数==============================
//=====================================================================
//函数名称：sendpcnodeFrame
//函数返回： 无
//参数说明： length：待发送数据的长度；data：待发送数据缓冲区。
//功能概要：通过pcnode发送指定长度的字节数组。
//更新记录：20180602，wb；
//=====================================================================
void sendpcnodeFrame(uint_16 length,uint_8 *data)
{
	uint_16 crc,len;

	len = length;
	//计算得到CRC校验码
//	crc = crc16(data,length);
	//发送帧头
	uart_send1(UART_NO,pcnodeFrameHead[0]);
	uart_send1(UART_NO,pcnodeFrameHead[1]);
	//发送帧长
	uart_send1(UART_NO,len>>8);
	uart_send1(UART_NO,len);
	//发送帧数据
	uart_sendN(UART_NO,len,data);
    //发送校验码
//	uart_send1(UART_NO,crc>>8);
//	uart_send1(UART_NO,crc);
	//发送帧尾
	uart_send1(UART_NO,pcnodeFrameTail[0]);
	uart_send1(UART_NO,pcnodeFrameTail[1]);
}

//======================================================================
//函数名称：historyCheck
//函数返回：0:数据有效；1：数据无效
//参数说明：无
//功能概要：获取系统时间
//======================================================================
uint_8 historyCheck(uint_16 data)
{
	//声明局部变量
	uint_8 i;
	uint_64 lstime;
	uint_64 timechange;
	static uint_64 timeget = 0;

	//记录收到数据的时间
	lstime = sysTimeGet();
	timechange = lstime - timeget;
	if(timechange < 6)
	{
		//如果两帧数据校验和不同
		if(gcRFHistory != data)
		{
			//将新数据帧的校验和保存起来
			gcRFHistory = data;
			timeget = lstime;
			return 0;
		}
		else
			return 1;
	}
	else
	{
		gcRFHistory = data;
		timeget = lstime;
		return 0;
	}
}
