
/******************************************************************************
版权所有：	
文件名称：	e2prom_emu.c
文件版本：	01.01
创建作者:	   sunxi
创建日期：	2012-07-13
功能说明：	e2prom仿真程序。
其它说明：	
修改记录：
*/

/*------------------------------- 头文件 --------------------------------------
*/
#include "bspconfig.h"
#include "i2c.h"
#include "ustimer.h"
#include "gpio.h"
#include "e2prom.h"

#include "rt.h"

/*------------------------------- 宏定义 --------------------------------------
*/
#if CFG_BSP_DEBUG

#define _DEBUG_E2PROM

#endif



/*------------------------------ 全局变量 -------------------------------------
*/
int gf_e2prom;

/*------------------------------ 函数声明 -------------------------------------
*/
int e2prom_erase(uint32_t offset,uint32_t length);

/*------------------------------ 外部函数 -------------------------------------
*/

/******************************************************************************
函数名称：	e2prom_init
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-06
函数说明：	e2prom初始化。
参数说明：	无
返回值：  	成功返回0.
修改记录：	
*/
int e2prom_init(void)
{
	int len;
	// 创建并打开文件
	gf_e2prom = rt_file_open("/app/data/e2prom.bin", O_CREAT|O_RDWR, 0);
	if(IS_ERR(gf_e2prom))
	{
	    printf("e2prom file open err!\r\n");
		return -1;
	}

	// 检查文件长度是否正确
	len = rt_file_getfile_size(gf_e2prom);
	if(len < 0)
	{
		rt_file_close(gf_e2prom, 0);
		gf_e2prom = -1;
		return -2;
	}
	if(len == CFG_E2PROM_SIZE)
	{
		return 0;
	}

	//如果文件长度不为0，说明e2prom被破坏，不修改内容，直接错误返回，
	//方便以后问题查找。
	if(len != 0)
	{
		rt_file_close(gf_e2prom, 0);
		gf_e2prom = -1;
		return -3;
	}

	// 如果文件长度为0，初始化e2prom 文件
	if(e2prom_erase(0, CFG_E2PROM_SIZE) != 0)
	{
		rt_file_close(gf_e2prom, 0);
		gf_e2prom = -1;
		return -4;
		
	}
	
	return 0;
}

int e2prom_reinit(void)
{
	if(gf_e2prom < 0) // 定值文件未打开
	{
		// 创建并打开文件
		gf_e2prom = rt_file_open("/app/data/e2prom.bin", O_CREAT|O_RDWR, 0);
		if(IS_ERR(gf_e2prom))
		{
			return -1;
		}
		rt_err_clr(ERR_CODE_INIT_E2PROM, 0);
	}
	e2prom_erase(0, CFG_E2PROM_SIZE);

	return 0;
}



int e2prom_exit(void)
{
	if(gf_e2prom >= 0)
	{
		rt_file_close(gf_e2prom, 0);
		gf_e2prom = -1;
	}

	return 0;
}


/******************************************************************************
函数名称：	e2prom_read
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-06
函数说明：	从E2PROM中读出数据。
参数说明：	
	offset(in)：需要读的数据在E2PROM中的偏移量，和length之和不能大于
				CFG_E2PROM_SIZE.
	buffer(out):读出数据的buffer。
	length(in):	需要读出数据的长度，和offset之和不能大于CFG_E2PROM_SIZE。
返回值：  	成功返回0.
修改记录：	
*/
int e2prom_read(uint32_t offset, unsigned char *buffer, uint32_t length)
{
	off_t pos;
	int ret;
	
	if(gf_e2prom < 0)
	{
		return -1;
	}
	//检查参数
	if(buffer == 0 || (offset + length) > CFG_E2PROM_SIZE)
	{
		return -1;
	}

	if(length == 0)
	{
		return 0;
	}

	pos = offset;
	ret = rt_file_read(gf_e2prom, buffer, length, &pos);
	if(ret != (int)length)
	{
		return -2;
	}

	return 0;
}


/******************************************************************************
函数名称：	e2prom_write
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-06
函数说明：	将数据写入E2PROM中。注意：E2PROM按页写的速度比按字节写的速度快，
			所以如果应用程序将要写入的数据组织成
参数说明：	
	offset(in)：需要写入的数据在E2PROM中的偏移量，和length之和不能大于
				CFG_E2PROM_SIZE.
	buffer(in):写入数据的buffer。
	length(in):	需要写入数据的长度，和offset之和不能大于CFG_E2PROM_SIZE。
返回值：  	成功返回0.
修改记录：	
*/
int e2prom_write(uint32_t offset, unsigned char *buffer, uint32_t length)
{
	off_t pos;
	int ret;
	
	if(gf_e2prom < 0)
	{
		return -1;
	}
	//检查参数
	if(buffer == 0 || (offset + length) > CFG_E2PROM_SIZE)
	{
		return -1;
	}
	if(length == 0)
	{
		return 0;
	}

	pos = offset;
	ret = rt_file_write(gf_e2prom, buffer, length, &pos);
	if(ret != (int)length)
	{
		return -2;
	}

	return 0;
}


int e2prom_erase(uint32_t offset, uint32_t length)
{
	unsigned char *buf;
	off_t off;
	size_t len;
	int ret;

	if(gf_e2prom < 0)
	{
		return -1;
	}

	buf = rt_malloc(CFG_E2PROM_SIZE);
	if(buf == NULL)
	{
		return -2;
	}

	memset(buf,-1,CFG_E2PROM_SIZE);
	off = offset;

	while(length)
	{
		len = length>CFG_E2PROM_SIZE ? CFG_E2PROM_SIZE:length;
		length -= len;
		ret = rt_file_write(gf_e2prom, buf, len, &off);
		if(ret != (int)len)
		{
			rt_free(buf);
			return -3;
		}
	}

	rt_free(buf);
	return 0;
}


/*------------------------------ 内部函数 -------------------------------------
*/


/*------------------------------ 测试函数 -------------------------------------
*/
#ifdef _DEBUG_E2PROM

#include "rt.h"
#define E2PROM_TEST_SIZE	1044 //必须是偶数

int e2prom_test(void)
{
	int ret;
	unsigned long us0,us;
	unsigned long i,offset,length;
	static unsigned short buffer[E2PROM_TEST_SIZE/2];
	
	rt_printf("e2prom_test start...\r\n");
	
	offset = 0;
	while(offset < CFG_E2PROM_SIZE)
	{
		//写
		length = (CFG_E2PROM_SIZE - offset) > E2PROM_TEST_SIZE ? E2PROM_TEST_SIZE : (CFG_E2PROM_SIZE - offset);
		for(i=0;i<length/2;i++)
		{
			
			buffer[i] = (unsigned short)(offset + i + 0x5555);
		}
		us0 = ustimer_get_origin();
		ret = e2prom_write(offset,(unsigned char *)buffer,length);
		us = ustimer_get_duration(us0);
		rt_printf("e2prom_write:(offset=%lu,ret=%d,us=%lu)\r\n",offset,ret,us);
		if(ret != 0)
		{
			
			break;
		}
		
		offset += length;
	}
	
	offset = 0;
	while(offset < CFG_E2PROM_SIZE)
	{
		//读
		length = (CFG_E2PROM_SIZE - offset) > E2PROM_TEST_SIZE ? E2PROM_TEST_SIZE : (CFG_E2PROM_SIZE - offset);
		memset(buffer,0,E2PROM_TEST_SIZE);
		us0 = ustimer_get_origin();
		ret = e2prom_read(offset,(unsigned char *)buffer,length);
		us = ustimer_get_duration(us0);
		rt_printf("e2prom_read:(offset=%lu,ret=%d,us=%lu)\r\n",offset,ret,us);
		
		if(ret != 0)
		{
			
			break;
		}
		
		//比较
		for(i=0;i<length/2;i++)
		{
			if(buffer[i] != (unsigned short)(offset + i + 0x5555))
			{
				
				break;
			}
		}
		if(i== length/2)
		{
			
			rt_printf("compare ok(offset=%lu,i=%lu)!\r\n",offset,i);
		}
		else
		{
			rt_printf("compare error(offset=%lu,i=%lu)!\r\n",offset,i);
			break;
		}
		
		offset += length;
		
	}
	
	if(offset == CFG_E2PROM_SIZE)
	{
		
		rt_printf("e2prom_test ok!\r\n\n");
	}
	else
	{
		
		rt_printf("e2prom_test fail!\r\n\n");
	}
	
	return 0;
}

#endif


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