/******************************************************************************
版权所有：	文件名称：	shm_comm_packet.c
文件名称：	shm_comm_packet.c
文件版本：	01.01
创建作者：	sunxi
创建日期：	2022-04-25
功能说明：	共享内存通信打包
其它说明：
修改记录：
*/

/*------------------------------- 头文件 --------------------------------------
*/
#include    "head.h"  
#include  "shm.h"

/*------------------------------- 宏定义 --------------------------------------
*/



/*------------------------------ 类型结构 -------------------------------------
*/



/*------------------------------ 函数声明 -------------------------------------
*/



/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/


/******************************************************************************
函数名称：	shm_comm_packet_write
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-04-25
函数说明：	向共享内存写入数据(自动处理A,B,crc).
参数说明：	
addr：共享内存的地址
data：写入数据
len:写入数据长度

返回值：	成功返回写入数据的长度, 失败返回-1
修改记录：	

使用说明：
输入参数data为带有A,B和crc的结构体，len为整个结构体的长度
应用层不需要理会A,B和crc.

*/
int shm_comm_packet_write(uint32_t addr, uint8_t *data, uint32_t len)
{
	uint16_t A;
	int ret;
	uint16_t crc = 0;


	if(data == NULL)
		return -1;
	if(len == 0 )
		return -1;

	//A++
	memcpy(&A,&SHM_BASE_W[addr],2); 
	A++;
	memcpy(&SHM_BASE_W[addr],&A,2); 

	//写数据区
	ret = shm_write(addr+4, data+4, len-6);
	if(ret == -1)
		return -1;

	//crc
	crc = CrcStr(data+4, len-6);//CRC 
	memcpy(&SHM_BASE_W[addr+len-2],&crc,2);

	//B++
	memcpy(&SHM_BASE_W[addr+2],&A,2); //A和B保证一样

	return ret+6;//加上A,B,crc的长度
}

/******************************************************************************
函数名称：	shm_comm_packet_read
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-04-25
函数说明：	读取共享内存的数据(自动处理A,B,crc).
参数说明：	
addr：所以读取共享内存的地址
len：需要读取数据的长度
out_data：输出buf
out_data_size:输出buf的长度

返回值：	
	成功返回读取数据的长度, 
	失败返回 <0
修改记录：	

使用说明：
输入参数out_data为带有A,B和crc的结构体，len为整个结构体的长度
应用层不需要理会A,B和crc.

*/
int shm_comm_packet_read(uint32_t addr, uint32_t len, uint8_t *out_data, uint32_t out_data_size)
{
	uint16_t A,B;
	//uint16_t last_A = 0;
	//uint16_t last_B = 0;

	
	int ret;
	uint16_t crc = 0;
	uint16_t read_crc = 0;

	//shm_read(addr, 2, (uint8_t*)&last_A, sizeof(last_A));
	//shm_read(addr+2, 2, (uint8_t*)&last_B, sizeof(last_B));
	//printf("last_A=%X, last_B=%X\n", last_A,last_B);

	//if(last_A == last_B)
	{
		//idle
		ret = shm_read(addr, len, out_data, out_data_size);
		
		A = out_data[0]+((uint16_t)out_data[1]<<8);
		B = out_data[2]+((uint16_t)out_data[3]<<8);
		//printf("A=%X, B=%X\n", A,B);

		if((A == B) )//&& (A == last_A))
		{
			//在拷贝过程中，数据没有被修改
			crc = CrcStr(out_data+4,len-6);
			read_crc = out_data[len-2]+((uint16_t)out_data[len-1]<<8);
			//printf("cal crc=%04X, read crc=%04X\n",	crc,read_crc);
			if(crc != read_crc)
			{
				//crc error
				return -3;
			}

		}
		else
		{
			//busy 裸核正在写数据
			return -2;

		}

	}
	//else
	//{
		//busy 裸核正在写数据
	//	return -2;
		
	//}

	return ret;
}

/******************************************************************************
函数名称：	shm_comm_packet_read_noABcrc
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-04-25
函数说明：	读取共享内存的数据(结构体不存在A,B,crc).
参数说明：	
addr：所以读取共享内存的地址
len：需要读取数据的长度
out_data：输出buf
out_data_size:输出buf的长度

返回值：	
	成功返回读取数据的长度, 
	失败返回 <0
修改记录：	

使用说明：
 如：Ad7616采样点结构
 本函数只处理不含有A,B和crc的结构体

*/
int shm_comm_packet_read_noABcrc(uint32_t addr, uint32_t len, uint8_t *out_data, uint32_t out_data_size)
{
	int ret;

	ret = shm_read(addr, len, out_data, out_data_size);

	return ret;
}

/*------------------------------ 测试函数 -------------------------------------
*/

typedef struct testtt_t
{
	uint16_t A;
	uint16_t B;
	uint16_t rc[16]; 
	uint16_t crc;
}testtt_t;

testtt_t aabfd,readaaaa;

void shm_comm_test(void)
{
	int i;
	int ret = 0;
	

	for(i=0;i<16;i++)
	{
		aabfd.rc[i]=i+2;
		printf("aabfd.rc[%d]=%X\n",i,aabfd.rc[i]);

	}
		
	ret = shm_comm_packet_write(0,(uint8_t*)&aabfd,sizeof(aabfd));
	printf("shm_comm_packet_write ret=%d\n",ret);

	if(ret > 0)
	{
		for(i=0;i<ret;i++)
		{
			printf("%X ",SHM_BASE_W[i]);
		}
		printf("\n ");

	}

	ret = shm_comm_packet_read(0, sizeof(readaaaa), (uint8_t*)&readaaaa, sizeof(readaaaa));
	printf("shm_comm_packet_read ret=%d\n",ret);

	if(ret > 0)
	{
		for(i=0;i<16;i++)
		{
			printf("%X ",readaaaa.rc[i]);
		}
		printf("\n ");

	}

}

/*------------------------------ 文件结束 -------------------------------------
*/

